1. 程式人生 > 程式設計 >利用Flutter實現“孔雀開屏”的動畫效果

利用Flutter實現“孔雀開屏”的動畫效果

前言

今天分享一個類似“孔雀開屏”的動畫效果,開啟新的頁面時,新的頁面從螢幕右上角以圓形逐漸開啟到全屏。

先來看下具體的效果

利用Flutter實現“孔雀開屏”的動畫效果

不知道這種效果大家叫什麼名字?如果有更合適的名字可以在評論處告訴我,下面來說下如何實現此效果。

在使用Navigator進入一個新的頁面時,通常用法如下:

Navigator.of(context).push(MaterialPageRoute(
 builder: (context){
  return PageB();
 }
));

MaterialPageRoute就包含了切換頁面時的動畫效果,在iOS上效果是左右滑動切換,在Android上效果是上下滑動,如果想要自定義切換效果如何實現呢?答案是使用PageRouteBuilder,用法如下:

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

在pageBuilder函式中使用animation返回新頁面的動畫效果即可。

新的頁面以圓形效果逐漸開啟,注意並沒有縮放效果,所以新的頁面是被裁減的,新的頁面以右上角為圓心,半徑逐漸變大進行裁切,就是我們想要的效果。

通過上面的分析,使用ClipPath對新的頁面進行裁切

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

重點是CirclePath,這就是裁切的路徑,

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;
 }
}

由於Path沒有直接新增圓形的API函式,因此使用橢圓方法,只需將橢圓的矩形區域設定為正方形,那麼裁切出來的就是圓形。

半徑的最大值並不是螢幕的寬或者高,而是螢幕的對角線長度。

由於是從右上角開始,而且裁切的矩形區域必須是正方形,所以裁切的矩形區域是超出頁面區域的。

如果很多頁面都用到了這個效果,可以進行封裝,類似於MaterialPageRoute,封裝如下:

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> secondaryAnimation) {
  return AnimatedBuilder(
   animation: animation,child) {
    return ClipPath(
     clipper: CirclePath(animation.value),);
   },child: builder(context),);
 }
}

使用

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

如果你檢視CupertinoPageRoute、MaterialPageRoute、PageRouteBuilder的原始碼,你會發現這3個都是繼承自PageRoute,所以,不知不覺我們又學會了自定義路由。

總結

到此這篇關於利用Flutter實現“孔雀開屏”的動畫效果的文章就介紹到這了,更多相關Flutter動畫效果內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!