Flutter动画 5 - Flutter内置动画组件

2021-05-14  本文已影响0人  神经骚栋

概述


前几篇文章我们都是使用Flutter中的AnimationController、Animation以及Tween来实现我们的动画效果,如果我们只想实现一些简单动画,该怎么办呢?今天我们就一起了解Flutter中内置的动画组件.接下来,我们就来分类来看一下Futter内置的动画组件.



Animation组件 功能
DecoratedBoxTransition DecoratedBox的动画版本,可以给它的Decoration不同属性使用动画
FadeTransition 对透明度使用动画的widget
PositionedTransition Positioned的动画版本,它需要一个特定的动画来将孩子的位置从动画的生命周期的起始位置移到结束位置。
RotationTransition 对widget使用旋转动画
ScaleTransition 对widget使用缩放动画
SizeTransition 对widget使用尺寸相关动画
SlideTransition 对相对于其正常位置的某个位置之间使用动画



Animation组件 功能
AnimatedPadding 在padding发生变化时会执行过渡动画到新状态
AnimatedPositioned 配合Stack一起使用,当定位状态发生变化时会执行过渡动画到新的状态。
AnimatedOpacity Opacity的动画版本,在给定的透明度变化时,自动地在给定的一段时间内改变child的Opacity
AnimatedAlign 当alignment发生变化时会执行过渡动画到新的状态。
AnimatedContainer 当Container属性发生变化时会执行过渡动画到新的状态。
AnimatedDefaultTextStyle 当字体样式发生变化时,子组件中继承了该样式的文本组件会动态过渡到新样式。

本篇文章大部分示例直接摘抄官方,具体可去 动画&Motion Widget 查询.(PS:写不动了,着实写不动了. 😂 😂 😂 )

需要外部Animation支持的组件示例


DecoratedBoxTransition示例

final DecorationTween decorationTween = DecorationTween(
  begin: BoxDecoration(
    color: const Color(0xFFFFFFFF),
    border: Border.all(style: BorderStyle.none),
    borderRadius: BorderRadius.circular(60.0),
    shape: BoxShape.rectangle,
    boxShadow: const <BoxShadow>[
      BoxShadow(
        color: Color(0x66666666),
        blurRadius: 10.0,
        spreadRadius: 3.0,
        offset: Offset(0, 6.0),
      )
    ],
  ),
  end: BoxDecoration(
    color: const Color(0xFFFFFFFF),
    border: Border.all(
      style: BorderStyle.none,
    ),
    borderRadius: BorderRadius.zero,
    // No shadow.
  ),
);

late AnimationController _controller = AnimationController(
  vsync: this,
  duration: const Duration(seconds: 3),
)..repeat(reverse: true);

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

 @override
 Widget build(BuildContext context) {
   return Container(
     color: Colors.white,
     child: Center(
       child: DecoratedBoxTransition(
         position: DecorationPosition.background,
         decoration: decorationTween.animate(_controller),
         child: Container(
           width: 200,
           height: 200,
           padding: const EdgeInsets.all(10),
           child: const FlutterLogo(),
         ),
       ),
     ),
   );
 }

FadeTransition示例

late AnimationController _controller = AnimationController(
  duration: const Duration(seconds: 2),
  vsync: this,
)..repeat(reverse: true);
late Animation<double> _animation = CurvedAnimation(
  parent: _controller,
  curve: Curves.easeIn,
);

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

@override
Widget build(BuildContext context) {
  return Container(
    color: Colors.white,
    child: FadeTransition(
      opacity: _animation,
      child: const Padding(
        padding: EdgeInsets.all(8),
        child: FlutterLogo()
      ),
    ),
  );
}

PositionedTransition示例

late AnimationController _controller = AnimationController(
  duration: const Duration(seconds: 2),
  vsync: this,
)..repeat(reverse: true);

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

@override
Widget build(BuildContext context) {
  final double smallLogo = 100;
  final double bigLogo = 200;

  return LayoutBuilder(
    builder: (context, constraints) {
      final Size biggest = constraints.biggest;
      return Stack(
        children: [
          PositionedTransition(
            rect: RelativeRectTween(
              begin: RelativeRect.fromSize(Rect.fromLTWH(0, 0, smallLogo, smallLogo), biggest),
              end: RelativeRect.fromSize(Rect.fromLTWH(biggest.width - bigLogo, biggest.height - bigLogo, bigLogo, bigLogo), biggest),
            ).animate(CurvedAnimation(
              parent: _controller,
              curve: Curves.elasticInOut,
            )),
            child: Padding(
              padding: const EdgeInsets.all(8),
              child: FlutterLogo()
            ),
          ),
        ],
      );
    },
  );
}

RotationTransition示例

late AnimationController _controller = AnimationController(
  duration: const Duration(seconds: 2),
  vsync: this,
)..repeat(reverse: true);
late Animation<double> _animation = CurvedAnimation(
  parent: _controller,
  curve: Curves.elasticOut,
);

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

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: Center(
      child: RotationTransition(
        turns: _animation,
        child: const Padding(
          padding: EdgeInsets.all(8.0),
          child: FlutterLogo(size: 150.0),
        ),
      ),
    ),
  );
}

ScaleTransition示例

late AnimationController _controller = AnimationController(
  duration: const Duration(seconds: 2),
  vsync: this,
)..repeat(reverse: true);
late Animation<double> _animation = CurvedAnimation(
  parent: _controller,
  curve: Curves.fastOutSlowIn,
);

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

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: Center(
      child: ScaleTransition(
        scale: _animation,
        child: const Padding(
          padding: EdgeInsets.all(8.0),
          child: FlutterLogo(size: 150.0),
        ),
      ),
    ),
  );
}

SizeTransition示例

late AnimationController _controller = AnimationController(
  duration: const Duration(seconds: 3),
  vsync: this,
)..repeat();
late Animation<double> _animation = CurvedAnimation(
  parent: _controller,
  curve: Curves.fastOutSlowIn,
);

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

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: SizeTransition(
      sizeFactor: _animation,
      axis: Axis.horizontal,
      axisAlignment: -1,
      child: Center(
          child: FlutterLogo(size: 200.0),
      ),
    ),
  );
}

SlideTransition示例

class _MyStatefulWidgetState extends State<MyStatefulWidget> with SingleTickerProviderStateMixin {
  late AnimationController _controller = AnimationController(
    duration: const Duration(seconds: 2),
    vsync: this,
  )..repeat(reverse: true);
  late Animation<Offset> _offsetAnimation = Tween<Offset>(
    begin: Offset.zero,
    end: const Offset(1.5, 0.0),
  ).animate(CurvedAnimation(
    parent: _controller,
    curve: Curves.elasticIn,
  ));

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

  @override
  Widget build(BuildContext context) {
    return SlideTransition(
      position: _offsetAnimation,
      child: const Padding(
        padding: EdgeInsets.all(8.0),
        child: FlutterLogo(size: 150.0),
      ),
    );
  }
}

不需要外部Animation支持组件示例


AnimatedPadding示例

double padValue = 0.0;
_updatePadding(double value) {
  setState(() {
    padValue = value;
  });
}

@override
Widget build(BuildContext context) {
  return Column(
    mainAxisAlignment: MainAxisAlignment.center,
    children: [
      AnimatedPadding(
        padding: EdgeInsets.all(padValue),
        duration: const Duration(seconds: 2),
        curve: Curves.easeInOut,
        child: Container(
          width: MediaQuery.of(context).size.width,
          height: MediaQuery.of(context).size.height / 5,
          color: Colors.blue,
        ),
      ),
      Text('Padding: $padValue'),
      ElevatedButton(
        child: Text('Change padding'),
        onPressed: () {
          _updatePadding(padValue == 0.0 ? 100.0 : 0.0);
        }
      ),
    ],
  );
}

AnimatedPositioned示例

bool selected = false;

@override
Widget build(BuildContext context) {
  return Container(
    width: 200,
    height: 350,
    child: Stack(
      children: [
        AnimatedPositioned(
          width: selected ? 200.0 : 50.0,
          height: selected ? 50.0 : 200.0,
          top: selected ? 50.0 : 150.0,
          duration: Duration(seconds: 2),
          curve: Curves.fastOutSlowIn,
          child: GestureDetector(
            onTap: () {
              setState(() {
                selected = !selected;
              });
            },
            child: Container(
              color: Colors.blue,
              child: Center(child: Text('Tap me')),
            ),
          ),
        ),
      ],
    ),
  );
}

AnimatedOpacity示例

class LogoFade extends StatefulWidget {
  @override
  createState() => LogoFadeState();
}

class LogoFadeState extends State<LogoFade> {
  double opacityLevel = 1.0;

  void _changeOpacity() {
    setState(() => opacityLevel = opacityLevel == 0 ? 1.0 : 0.0);
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        AnimatedOpacity(
          opacity: opacityLevel,
          duration: Duration(seconds: 3),
          child: FlutterLogo(),
        ),
        ElevatedButton(
          child: Text('Fade Logo'),
          onPressed: _changeOpacity,
        ),
      ],
    );
  }
}

AnimatedAlign示例

bool selected = false;

@override
Widget build(BuildContext context) {
  return GestureDetector(
    onTap: () {
      setState(() {
        selected = !selected;
      });
    },
    child: Center(
      child: Container(
        width: 250.0,
        height: 250.0,
        color: Colors.red,
        child: AnimatedAlign(
          alignment: selected ? Alignment.topRight : Alignment.bottomLeft,
          duration: const Duration(seconds: 1),
          curve: Curves.fastOutSlowIn,
          child: const FlutterLogo(size: 50.0),
        ),
      ),
    ),
  );
}

AnimatedContainer示例

bool selected = false;

@override
Widget build(BuildContext context) {
  return GestureDetector(
    onTap: () {
      setState(() {
        selected = !selected;
      });
    },
    child: Center(
      child: AnimatedContainer(
        width: selected ? 200.0 : 100.0,
        height: selected ? 100.0 : 200.0,
        color: selected ? Colors.red : Colors.blue,
        alignment: selected ? Alignment.center : AlignmentDirectional.topCenter,
        duration: Duration(seconds: 2),
        curve: Curves.fastOutSlowIn,
        child: FlutterLogo(size: 75),
      ),
    ),
  );
}

AnimatedDefaultTextStyle示例

  var duration = Duration(seconds: 5);

  TextStyle _style = TextStyle(color: Colors.black);

  @override
  Widget build(BuildContext context) {
    return AnimatedDefaultTextStyle(
      child: GestureDetector(
        child: Text("hello world"),
        onTap: () {
          setState(() {
            _style = TextStyle(
              color: Colors.blue,
              decorationStyle: TextDecorationStyle.solid,
              decorationColor: Colors.blue,
            );
          });
        },
      ),
      style: _style,
      duration: duration,
    );
  }       

结语


整体上来说,如果是实现比较简单的动画可以直接使用Flutter内置的动画组件,可以大大减少代码量.本篇文章算是一个记录吧,如果深入,可自行查看下面的参考内容.

欢迎持续关注骚栋,有任何问题欢迎联系骚栋.

动画&Motion Widget
动画过渡组件
上一篇下一篇

猜你喜欢

热点阅读