🍭 about ClipPath

We’ve all used clipXX-related components to make rounded rectangles/circles handy, but ClipPath is the only way to implement odd-looking widgets such as pentagons/arcs.

To learn more about ClipPath, go directly to the website for the documentation, introduced as follows:

A widget that clips its child using a path.

Calls a callback on a delegate whenever the widget is to be painted. The callback returns a path and the widget prevents the child from painting outside the path.

Clipping to a path is expensive.

Use path to cut the child widget.

Whenever the widget is drawn, the callback is invoked on the delegate. The callback function returns a path, and the widget prevents the Child from being drawn outside the path.

Tailoring paths is expensive.

In general, this is to cut the child widgets by path, but tailoring the path is expensive.

🦾 to see how to use

To see how this works, let’s first look at its constructor:

const ClipPath({
  Key key,
  this.clipper, // final CustomClipper<Path> clipper;
  this.clipBehavior = Clip.antiAlias,
  Widget child,
}) : assert(clipBehavior ! =null),
super(key: key, child: child);
Copy the code

First of all, you can see that there are actually two parameters needed, one is clipper, the other is child.

Child is the clipper clipper component. Write the child. The rest is the Clipper.

Take a look at clipper’s source code:

/// CustomClipper
abstract class CustomClipper<T> {
  /// Creates a custom clipper.
  ///
  /// The clipper will update its clip whenever [reclip] notifies its listeners.
  const CustomClipper({ Listenable reclip }) : _reclip = reclip;

  final Listenable _reclip;

  // return the description of the clip -> T
  T getClip(Size size);

  /// Whether to re-clip
  bool shouldReclip(covariant CustomClipper<T> oldClipper);

}
Copy the code

A few methods have been removed, leaving only the ones we need to rewrite, the chief of which is T getClip(Size Size).

The generic type passed in ClipPath is , CustomClipper

/ CustomClipper

/ CustomClipper


So you just need to define your own Path to implement widgets of any shape.

😼 start implementing custom shaped widgets

Let’s implement the following shapes (original above, cropped below) :

To sum up, simply implement a CustomClipper and pass in the Clipper parameter to ClipPath.

The code is as follows:

class MyClipper extends CustomClipper<Path> {

  @override
  Path getClip(Size size) {
    Path path = Path();
    // start at 60,0
    path.moveTo(60.0);
    // Second order Bezier curve drawing arc
    path.quadraticBezierTo(0.0.0.60);
    // connect to the bottom
    path.lineTo(0, size.height / 1.2);
    // Third order Bezier curve drawing arc
    path.cubicTo(size.width / 4, size.height, size.width / 4 * 3, size.height / 1.5, size.width, size.height / 1.2);
    // connect back again
    path.lineTo(size.width, 60);
    // Use the second order Bezier curve to draw the arc
    path.quadraticBezierTo(size.width - 60.60, size.width - 60.0);
    return path;
  }

  @override
  bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}
Copy the code

I won’t say the logic, it’s all in the comments.

🦴 summary

Because the consumption of ClipPath is quite high, so if you just want to cut a rounded corner, or recommend to use the built-in ClipRRect, such as their performance is better (official documentation says).

ClipPath also has a static method, ClipPath. Shape ().

You can also read this article by Zhang Fengjietri – [Flutter advanced plays-shape] Path in hand, the world I have.

This article is a detailed explanation of the Path gameplay, only you can think of, without it can not do! This static method is also explained at the end.

The code has been submitted to Github – Cropping Widget Demo.

If there are defects, I hope you put forward, learn together! 🤝