Today, I share an animation effect similar to “peacock’s screen”. When opening a new page, the new page gradually opens to the full screen from the top right corner of the screen in a circle.

Let’s look at the specific effects

I don’t know what this effect is called? Let me know in the comments if you have a better name, and here’s how to do it.

When using Navigator to enter a new page, the usual usage is as follows:

Navigator.of(context).push(MaterialPageRoute(
  builder: (context){
    returnPageB(); }));Copy the code

The MaterialPageRoute contains the animation effect when switching pages. On iOS, the effect is left and right to switch, and on Android, the effect is up and down. How to customize the switching effect? The answer is to use PageRouteBuilder as follows:

Navigator.of(context).push(PageRouteBuilder(pageBuilder:
    (BuildContext context, Animation<double> animation,
        Animation<double> secondaryAnimation) {
  ...
}));
Copy the code

Use animation in the pageBuilder function to return the animation of the new page.

The new page is gradually opened with a circular effect. Notice that there is no zoom effect, so the new page is cut. The new page is centered on the upper right corner of the circle, and the radius is gradually increased for cutting, which is the effect we want.

Using the above analysis, crop the new page using ClipPath

Navigator.of(context).push(PageRouteBuilder(pageBuilder:
    (BuildContext context, Animation<double> animation,
        Animation<double> secondaryAnimation) {
  return AnimatedBuilder(
    animation: animation,
    builder: (context, child) {
      return ClipPath(
        clipper: CirclePath(animation.value),
        child: child,
      );
    },
    child: PageB(),
  );
}));
Copy the code

The focus is on the CirclePath, which is the pruning path,

class CirclePath extends CustomClipper<Path> {
  CirclePath(this.value);

  final double value;

  @override
  Path getClip(Size size) {
    var path = Path();
    double radius =
        value * sqrt(size.height * size.height + size.width * size.width);
    path.addOval(Rect.fromLTRB(
        size.width - radius, -radius, size.width + radius, radius));
    return path;
  }

  @override
  bool shouldReclip(CustomClipper<Path> oldClipper) {
    return true; }}Copy the code

Since Path does not add a circle directly to the API function, using the ellipse method, you simply set the rectangular region of the ellipse to a square, and you will crop out a circle.

The maximum radius is not the width or height of the screen, but the diagonal length of the screen.

Since it starts in the upper right corner and the cropped rectangle must be square, the cropped rectangle is outside the page area.

If this effect is applied to many pages, it can be encapsulated, similar to the MaterialPageRoute, as follows:

class CirclePageRoute extends PageRoute {
  CirclePageRoute({
    @required this.builder,
    this.transitionDuration = const Duration(milliseconds: 500),
    this.opaque = true.this.barrierDismissible = false.this.barrierColor,
    this.barrierLabel,
    this.maintainState = true});final WidgetBuilder builder;

  @override
  final Duration transitionDuration;

  @override
  final bool opaque;

  @override
  final bool barrierDismissible;

  @override
  final Color barrierColor;

  @override
  final String barrierLabel;

  @override
  final bool maintainState;

  @override
  Widget buildPage(BuildContext context, Animation<double> animation,
      Animation<double> secondaryAnimation) {
    return AnimatedBuilder(
      animation: animation,
      builder: (context, child) {
        returnClipPath( clipper: CirclePath(animation.value), child: child, ); }, child: builder(context), ); }}Copy the code

use

Navigator.of(context).push(CirclePageRoute(builder: (context) {
  return PageB();
}));
Copy the code

If you look at the source code of CupertinoPageRoute, MaterialPageRoute, PageRouteBuilder, you will find that these three are inherited from PageRoute, so we have learned to customize the route.

communication

Old Meng Flutter blog address (nearly 200 controls usage) : laomengit.com