Flutter學習筆記(36)--經常使用內置動畫

如需轉載,請註明出處:Flutter學習筆記(36)--經常使用內置動畫html

Flutter給咱們提供了不少並且很好用的內置動畫,這些動畫僅僅須要簡單的幾行代碼就能夠實現一些不錯的效果,Flutter的動畫分爲補間動畫和基於物理的動畫,基於物理的動畫咱們先不說。git

補間動畫很簡單,Android裏面也有補間動畫,就是給UI設置初始的狀態和結束狀態,通過咱們定義的一段時間,系統去幫助咱們實現開始到結束的過渡變化,這就是補間動畫。github

今天咱們要看的Flutter的內置動畫就是補間動畫,根據Flutter提供的動畫組件,咱們去設置初始、結尾的狀態,而且定義一下這個變化過程所須要的時間,再通過系統的處理(其實就是setState())來達到動畫的效果。api

接下來咱們會寫一下經常使用的內置動畫組件,而且提供一下動畫效果的gif,方便你們更直觀的去理解。app

  • AnimatedContainer

看到Container咱們就會知道這是一個帶有動畫屬性的容器組件,這個組件能夠定義大小、顏色等屬性,那麼咱們是否是就能夠給這個組件設置初始和結束的大小及顏色的屬性值,而後經過系統來幫助咱們來補足中間過程的動畫呢?less

答案是能夠的,下面看一下demo和動畫效果:ide

class _MyHomePageState extends State<MyHomePage> {
  double _width = 100.0;
  double _height = 100.0;
  Color _color = Colors.red;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: AnimatedContainer(
        width: _width,
        height: _height,
        duration: Duration(seconds: 2),
        color: _color,
        curve: Curves.bounceInOut,
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            _width = 300.0;
            _height = 300.0;
            _color = Colors.green;
          });
        },
        tooltip: 'Increment',
        child: Icon(Icons.adjust),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

 

demo很簡單,就是先定義好組件初始的大小和顏色,點擊按鈕,在按鈕事件裏面去更改大小和顏色的屬性值。這裏惟一須要特別說一下就是curve這個屬性。函數

curve指的是動畫曲線?我開始的時候不理解這個動畫曲線是什麼意思,後來看了一組圖以後,豁然開朗。demo裏面curve咱們用的是Curves.bounceInOut。以下:post

 

它其實就是一個非線性的動畫的變化形式(變化過程)也能夠理解爲就是一種函數,也不知道這麼說你們能不能理解。學習

/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_bounce_in.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_bounce_in_out.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_bounce_out.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_decelerate.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_sine.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_quad.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_cubic.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_quart.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_quint.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_expo.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_circ.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_back.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_out.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_out_sine.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_out_quad.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_out_cubic.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_out_quart.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_out_quint.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_out_expo.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_out_circ.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_out_back.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_out.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_out_sine.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_out_quad.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_out_cubic.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_out_quart.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_out_quint.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_out_expo.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_out_circ.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_out_back.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_elastic_in.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_elastic_in_out.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_elastic_out.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_fast_out_slow_in.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_slow_middle.mp4}
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_linear.mp4}

 

這裏是每一種curve曲線的表現形式,你們能夠看看,也能夠在demo裏面多嘗試,或者能夠看另外一篇博客,有動畫曲線Curves 效果

  • AnimatedCrossFade

Flutter中文網:一個widget,在兩個孩子之間交叉淡入,並同時調整他們的尺寸。

我的說明:CrossFade,故名思意,淡入淡出,AnimatedCrossFade組件包含兩個子widget,一個firstChild一個secondChild,這兩個組件根據狀態(咱們本身定義的一個標識)改變狀態,

一個淡入,一個淡出,同時改變大小或顏色等屬性。

class _MyHomePageState extends State<MyHomePage> {
  bool _showFirst = true;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: AnimatedCrossFade(
        firstChild: Container(
          width: 100,
          height: 100,
          color: Colors.red,
          alignment: Alignment.center,
          child: Text('firstChild'),
        ),
        secondChild: Container(
          width: 200,
          height: 200,
          color: Colors.green,
          alignment: Alignment.center,
          child: Text('secondChild'),
        ),
        duration: Duration(seconds: 3),
        crossFadeState:
            _showFirst ? CrossFadeState.showFirst : CrossFadeState.showSecond,
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            _showFirst = false;
          });
        },
        tooltip: 'Increment',
        child: Icon(Icons.adjust),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

 

  • Hero

Hero經常使用於頁面跳轉的過長動畫,好比電商App有一個商品列表,列表的每一個item都有一張縮略圖,點擊會跳轉到詳情頁面,在Flutter中將圖片從一個路由飛到另外一個路由稱爲hero動畫,儘管相同的動做有時也稱爲 共享元素轉換

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Hero(
        tag: 'heroTag',
        child: ClipOval(
          child: Image.asset(
            'images/banner.png',
            width: 60,
            height: 60,
            fit: BoxFit.cover,
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            Navigator.push(context, MaterialPageRoute(builder: (_) {
              return new HeroPage();
            }));
          });
        },
        tooltip: 'Increment',
        child: Icon(Icons.adjust),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

 

詳情頁面:

import 'package:flutter/material.dart';

class HeroPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'HeroPage',
      home: Scaffold(
        appBar: AppBar(
          title: Text('HeroPage'),
        ),
        body: Center(
          child: GestureDetector(
            child: Hero(
              tag: 'heroTag',
              child: ClipOval(
                child: Image.asset(
                  'images/banner.png',
                  width: 300,
                  height: 300,
                  fit: BoxFit.cover,
                ),
              ),
            ),
            onTap: () {
              Navigator.pop(context);
            },
          ),
        ),
      ),
    );
  }
}

 

注:特別強調一下,爲了將兩個頁面的元素關聯起來,hero有個tag標識,先後兩個頁面的tag標識必須同樣,否則的話元素是關聯不起來的,也就意味着不會產生hero動畫。

1.同級tag不容許相同。

2.先後頁面想要有hero動畫,tag必須相同。

3.先後關聯起來的hero組件,其各自內部的child組件不是必須同樣的,就是說前面的hero的子組件能夠是image,後面的hero的子組件能夠是image之外的其餘組件。

  • AnimatedBuilder

class _MyHomePageState extends State<MyHomePage>
    with SingleTickerProviderStateMixin {
  Animation<double> _animation;
  AnimationController _animationController;

  @override
  void initState() {
    _animationController =
        AnimationController(duration: Duration(seconds: 3), vsync: this);
    _animation =
        new Tween(begin: 0.0, end: 200.0).animate(_animationController);
    _animationController.forward();
    super.initState();
  }

  @override
  void dispose() {
    _animationController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: AnimatedBuilder(
          animation: _animation,
          builder: (BuildContext context, Widget child) {
            return Center(
              child: Container(
                color: Colors.red,
                width: _animation.value,
                height: _animation.value,
                child: child,
              ),
            );
          },
        ));
  }
}

AnimationController:動畫控制器(定義動畫過程時長)。

Animation:動畫變化區間值(也能夠說是開始和結束的關鍵幀值),demo裏定義的值爲初始0,結束200。

_animation.value:關鍵幀值是0和200,_animation.value的值爲0--200之間連續變化的值(0-1-2-3-...-198-199-200)。

  • DecoratedBoxTransition

Decortated能夠給容器添加各類外觀裝飾,好比增長圓角、陰影等裝飾。DecoratedBox的動畫版本,能夠給它的Decoration不一樣屬性使用動畫

class _MyHomePageState extends State<MyHomePage>
    with SingleTickerProviderStateMixin {
  Animation<Decoration> _animation;
  AnimationController _animationController;

  @override
  void initState() {
    _animationController =
        AnimationController(duration: Duration(seconds: 3), vsync: this);
    _animation = DecorationTween(
            begin: BoxDecoration(
                borderRadius: BorderRadius.all(Radius.circular(0.0)),
                color: Colors.red),
            end: BoxDecoration(
                borderRadius: BorderRadius.all(Radius.circular(30.0)),
                color: Colors.green))
        .animate(_animationController);
    _animationController.forward();
    super.initState();
  }

  @override
  void dispose() {
    _animationController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(widget.title)),
      body: Center(
        child: DecoratedBoxTransition(
          decoration: _animation,
          child: Container(
            width: 100,
            height: 100,
          ),
        ),
      ),
    );
  }
}

  • FadeTransition

透明度變化動畫,由於透明度也是在0-1之間變化的,因此animation就還繼續用double類型的就能夠了。

class _MyHomePageState extends State<MyHomePage>
    with SingleTickerProviderStateMixin {
  Animation<double> _animation;
  AnimationController _animationController;

  @override
  void initState() {
    _animationController =
        AnimationController(duration: Duration(seconds: 2), vsync: this);
    _animation = Tween(begin: 1.0, end: 0.0).animate(_animationController);
    _animationController.forward();
    super.initState();
  }

  @override
  void dispose() {
    _animationController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(widget.title)),
      body: Center(
        child: FadeTransition(
          opacity: _animation,
          child: Container(
            width: 100,
            height: 100,
            decoration: BoxDecoration(
              color: Colors.red,
            ),
          ),
        ),
      ),
    );
  }
}

  • RotationTransition

旋轉動畫,對widget使用旋轉動畫 1~360°(Tween(begin: 0.0, end: 1.0))這裏的0-1指的是0°-360°

class _MyHomePageState extends State<MyHomePage>
    with SingleTickerProviderStateMixin {
  Animation<double> _animation;
  AnimationController _animationController;

  @override
  void initState() {
    _animationController =
        AnimationController(duration: Duration(seconds: 2), vsync: this);
    _animation = Tween(begin: 0.0, end: 1.0).animate(_animationController);
    _animationController.forward();
    super.initState();
  }

  @override
  void dispose() {
    _animationController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(widget.title)),
      body: Center(
        child: RotationTransition(
          turns: _animation,
          child: Container(
            width: 100,
            height: 100,
            decoration: BoxDecoration(
              color: Colors.red,
            ),
            child: Center(child: Text('data')),
          ),
        ),
      ),
    );
  }
}

  • ScaleTransition

縮放動畫,Tween(begin: 1.0, end: 0.2)指的是原大小的倍數,demo裏是由原大小縮小到原來的0.2倍。

class _MyHomePageState extends State<MyHomePage>
    with SingleTickerProviderStateMixin {
  Animation<double> _animation;
  AnimationController _animationController;

  @override
  void initState() {
    _animationController =
        AnimationController(duration: Duration(seconds: 2), vsync: this);
    _animation = Tween(begin: 1.0, end: 0.2).animate(_animationController);
    _animationController.forward();
    super.initState();
  }

  @override
  void dispose() {
    _animationController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(widget.title)),
      body: Center(
        child: ScaleTransition(
          scale: _animation,
          child: Container(
            width: 200,
            height: 200,
            decoration: BoxDecoration(
              color: Colors.red,
            ),
            child: Center(child: Text('data')),
          ),
        ),
      ),
    );
  }
}

  • SizeTransition

僅一個方向進行縮放

class _MyHomePageState extends State<MyHomePage>
    with SingleTickerProviderStateMixin {
  Animation<double> _animation;
  AnimationController _animationController;

  @override
  void initState() {
    _animationController =
        AnimationController(duration: Duration(seconds: 2), vsync: this);
    _animation = Tween(begin: 1.0, end: 0.2).animate(_animationController);
    _animationController.forward();
    super.initState();
  }

  @override
  void dispose() {
    _animationController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(widget.title)),
      body: Center(
        child: SizeTransition(
          axis: Axis.horizontal,
          sizeFactor: _animation,
          child: Center(
            child: Container(
              width: 200,
              height: 200,
              decoration: BoxDecoration(
                color: Colors.red,
              ),
              child: Center(child: Text('data')),
            ),
          ),
        ),
      ),
    );
  }
}

 

以上!有任何疑問歡迎留言!

相關文章
相關標籤/搜索