天天看點

Flutter 38: 圖解 Flutter 基本動畫 (二)

      小菜前兩天學習了以下 Animation 的基本動畫,接下來小菜學習以下稍微進階版的 Animation 動畫。

複合動畫

      小菜前兩天學習的主要是基本的單一動畫,當然多個動畫效果集一身也是毫無問題的,小菜接下來嘗試一個圖檔顯隐性和縮放同時循環使用的 Demo;

  1. addStatusListener 用來監聽目前動畫狀态,即開始或結束;
  2. addListener 用來堅挺動畫過程,可擷取實時 value 值;
AnimationController controller;
Animation<double> animation, sizeAnim;

@override
void initState() {
  super.initState();
  controller = AnimationController(
      duration: const Duration(milliseconds: 2000), vsync: this);
  animation = Tween(begin: 0.0, end: 1.0).animate(controller);
  sizeAnim = Tween(begin: 0.0, end: 180.0).animate(controller);
  animation.addStatusListener((status) {
    if (status == AnimationStatus.completed) {
      controller.reverse();
    } else if (status == AnimationStatus.dismissed) {
      controller.forward();
    }
  });
  sizeAnim.addStatusListener((status) {
    if (status == AnimationStatus.completed) {
      controller.reverse();
    } else if (status == AnimationStatus.dismissed) {
      controller.forward();
    }
  });
}

Widget bodyWid() {
  return Center(
      child: Opacity(
          opacity: animation.value,
          child: FlutterLogo(size: sizeAnim.value)));
}           

時間段動畫

      既然可以監聽動畫過程和動畫狀态,整體的動畫便可以靈活掌握;小菜接下來嘗試一下分時間段動畫,前 50% 顯隐性處理,後 50% 縮放處理;

AnimationController controller;
Animation<double> animation, sizeAnim;
@override
void initState() {
  super.initState();
  controller = AnimationController(duration: const Duration(milliseconds: 2000), vsync: this);
  
  animation = Tween<double>(
    begin: 0.0,
    end: 1.0,
  ).animate(CurvedAnimation(
      parent: controller, curve: Interval(0.0, 0.5, curve: Curves.ease)));
  sizeAnim = Tween<double>(
    begin: 100.0,
    end: 180.0,
  ).animate(CurvedAnimation(
      parent: controller,
      curve: Interval(0.5, 1.0, curve: Curves.fastOutSlowIn)));
}

Widget bodyWid() {
  return Center(
      child: Opacity(
          opacity: animation.value,
          child: FlutterLogo(size: sizeAnim.value)));
}           

自定義動畫

      動畫是靈活的,我們可以根據自己的需求自定義動畫效果,小菜嘗試一個圓環繞一個圓轉圈;

AnimationController controller;
Animation<double> animation;

@override
void initState() {
  super.initState();
  controller = AnimationController(duration: const Duration(milliseconds: 2000), vsync: this);
  animation = Tween(begin: -1.0, end: 1.0).animate(controller);
}

class AnimationCanvas extends CustomPainter {
  Animation<double> animation;
  AnimationCanvas(this.animation);
  Paint _paint = Paint()
    ..color = Colors.blue
    ..strokeWidth = 4.0
    ..style = PaintingStyle.stroke;

  @override
  void paint(Canvas canvas, Size size) {
    canvas.save();
    canvas.drawCircle(Offset(300, 300.0), 150.0, _paint);
    canvas.restore();
    canvas.save();

    canvas.translate(150 * sin(pi * animation.value), 150 * cos(pi * animation.value));
    canvas.drawCircle(Offset(300, 300.0), 10.0, _paint..color = Colors.red);
    canvas.restore();
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}           

Hero 動畫

      Hero 動畫是 Flutter 提供的飛入式動畫,主要用在頁面間切換時動畫,且傳回時動畫按原路傳回;使用時設定兩個頁面間 tag 一緻即可,友善簡潔;

Widget bodyWid04() {
  return Container(
      child: Padding(
          padding: EdgeInsets.all(10.0),
          child: GestureDetector(
              child: Row(children: <Widget>[
                Hero(tag: 'user_header', child: FlutterLogo(size: 50.0)),
                Padding(
                    padding: EdgeInsets.only(left: 12.0),
                    child: Text('Flutter Ptoto'))
              ]),
              onTap: () {
                Navigator.pushNamed(context, 'animateRoute01');
              })));
}           

      小菜學習了一下稍進階的動畫,如果有問題的煩請多多指導!

繼續閱讀