Flutter绘制指南09-动画曲线和方法

本节目标

[1] 认识动画器【曲线速率】的作用
[2] 绘制出Flutter内置的所有曲线效果常量
[3] 了解动画器的常用方法
[4] 了解动画器的状态,以及状态变化监听

一、动画速率曲线

动画曲线描述了动画运动过程中的速度变化曲率,比如开始运动很快,然后慢慢变慢。这样可以实现丰富的运动视觉效果。

动画曲线的核心是4个数字,他的本身是一个贝塞尔曲线。起止点固定。也就是说动画曲线在形式上速度表现就是两个控制点。FLUTTER中使用Curve类来表述。

1. 认识的使用

Curve是一个抽象类。它有很多实现子类。最通用的是Cubic。传入4个值。下面来看一下。如何使用CurveTeen来让动画的变化速率更加的具有曲线效果。

Curve --- 抽象类
	|--- FlippedCurve 翻转曲线
	|--- SawTooth 翻转曲线
	|--- Threshold 0~阈值 曲线

案例实现如下效果:红色小球在圈上运动。绿色小球向下运动。通过改变动画的速率曲线,查看效果。我们可以发现,通过添加曲线可以让运动在首尾慢,中间快。

在这里插入图片描述

代码实现

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        debugShowCheckedModeBanner: false,
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: Scaffold(
          body: Center(
            child: CurveBox(curve: Cubic(1, -0.06, 0.1, 1.2),),
          ),
        ));
  }
}
class CurveBox extends StatefulWidget {
  final Color color;
  final Curve curve;

  CurveBox({Key? key, this.color = Colors.lightBlue, this.curve = Curves.linear})
      : super(key: key);

  @override
  _CurveBoxState createState() => _CurveBoxState();
}

class _CurveBoxState extends State<CurveBox>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _angleAnimation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 3),
      vsync: this,
    );
    _angleAnimation = CurveTween(curve: widget.curve).animate(_controller);
    _controller.repeat();
  }

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

  @override
  Widget build(BuildContext context) {
    return CustomPaint(
      size: Size(100, 100),
      painter: CurveBoxPainter(_controller, _angleAnimation), // 背景
    );
  }
}

class CurveBoxPainter extends CustomPainter {
  final Animation<double> repaint; //
  Animation<double> angleAnimation;

  Paint _paint = Paint();

  CurveBoxPainter(this.repaint, this.angleAnimation) : super(repaint: repaint) {}

  @override
  void paint(Canvas canvas, Size size) {
    canvas.clipRect(Offset.zero & size);
    canvas.translate(size.width / 2, size.height / 2);
    _drawRing(canvas, size);
    _drawRedCircle(canvas, size);
    _drawGreenCircle(canvas, size);
  }

  //绘制环
  void _drawRing(Canvas canvas, Size size) {
    final double strokeWidth = 5;
    _paint
      ..color = Colors.blue
      ..style = PaintingStyle.stroke
      ..strokeWidth = strokeWidth;
    canvas.drawCircle(Offset.zero, size.width / 2 - strokeWidth, _paint);
  }

  // 绘制红球
  void _drawRedCircle(Canvas canvas, Size size) {
    canvas.save();
    canvas.rotate(angleAnimation.value * 2 * pi);
    _paint
      ..color = Colors.red
      ..style = PaintingStyle.fill;
    canvas.drawCircle(
        Offset.zero.translate(0, -(size.width / 2 - 5)), 5, _paint);
    canvas.restore();
  }

  // 绘制绿球
  void _drawGreenCircle(Canvas canvas, Size size) {
    canvas.save();
    canvas.translate(0,angleAnimation.value * (size.height-10));
    _paint
      ..color = Colors.green
      ..style = PaintingStyle.fill;
    canvas.drawCircle(
        Offset.zero.translate(0, -(size.width / 2 - 5)), 5, _paint);
    canvas.restore();
  }

  @override
  bool shouldRepaint(covariant CurveBoxPainter oldDelegate) =>
      oldDelegate.repaint != repaint;
}

2. Flutter所有内置的曲线效果

当我们将曲线效果颜色封装成一个组件之后,就可以非常轻松的实现下面的效果。这就是Flutter的魅力。一共41个曲线效果。

在这里插入图片描述

void main() {
  // 确定初始化
  WidgetsFlutterBinding.ensureInitialized();
  //横屏
  SystemChrome.setPreferredOrientations(
      [DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight]);
  //全屏显示
  SystemChrome.setEnabledSystemUIOverlays([]);

  runApp(MyApp());
}

class MyApp extends StatelessWidget {

  final curvesMap = {
    "linear": Curves.linear,
    "decelerate": Curves.decelerate,
    "fastLinearToSlowEaseIn": Curves.fastLinearToSlowEaseIn,
    "ease": Curves.ease,
    "easeIn": Curves.easeIn,
    "easeInToLinear": Curves.easeInToLinear,
    "easeInSine": Curves.easeInSine,
    "easeInQuad": Curves.easeInCubic,
    "easeInCubic": Curves.easeInCubic,
    "easeInQuart": Curves.easeInQuart,
    "easeInQuint": Curves.easeInQuint,
    "easeInExpo": Curves.easeInExpo,
    "easeInCirc": Curves.easeInCirc,
    "easeInBack": Curves.easeInBack,
    "easeOut": Curves.easeOut,
    "linearToEaseOut": Curves.linearToEaseOut,
    "easeOutSine": Curves.easeOutSine,
    "easeOutQuad": Curves.easeOutQuad,
    "easeOutCubic": Curves.easeOutCubic,
    "easeOutQuart": Curves.easeOutQuart,
    "easeOutQuint": Curves.easeOutQuint,

    "easeOutExpo": Curves.easeOutExpo,
    "easeOutCirc": Curves.easeOutCirc,
    "easeOutBack": Curves.easeOutBack,
    "easeInOut": Curves.easeInOut,
    "easeInOutSine": Curves.easeInOutSine,
    "easeInOutQuad": Curves.easeInOutQuad,
    "easeInOutCubic": Curves.easeInOutCubic,
    "easeInOutQuart": Curves.easeInOutQuart,
    "easeInOutQuint": Curves.easeInOutQuint,
    "easeInOutExpo": Curves.easeInOutExpo,
    "easeInOutCirc": Curves.easeInOutCirc,
    "easeInOutBack": Curves.easeInOutBack,
    "fastOutSlowIn": Curves.fastOutSlowIn,
    "slowMiddle": Curves.slowMiddle,
    "bounceIn": Curves.bounceIn,
    "bounceOut": Curves.bounceOut,
    "bounceInOut": Curves.bounceInOut,
    "elasticIn": Curves.elasticIn,
    "elasticInOut": Curves.elasticInOut,
    "elasticOut": Curves.elasticOut,
  };

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        debugShowCheckedModeBanner: false,
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: Scaffold(
          body: Center(
            child:
            Wrap(
              runSpacing: 10,
              children: curvesMap.keys.map((e) => Column(
                mainAxisSize: MainAxisSize.min,
                children: [
                  CurveBox(curve: curvesMap[e]!,),
                  SizedBox(height: 3,),
                  Text(e,style: TextStyle(fontSize: 10),)
                ],
              )).toList(),
            ),
          ),
        ));
  }
}
class CurveBox extends StatefulWidget {
  final Color color;
  final Curve curve;

  CurveBox({Key? key, this.color = Colors.lightBlue, this.curve = Curves.linear})
      : super(key: key);

  @override
  _CurveBoxState createState() => _CurveBoxState();
}

class _CurveBoxState extends State<CurveBox>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _angleAnimation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 3),
      vsync: this,
    );
    _angleAnimation = CurveTween(curve: widget.curve).animate(_controller);
    _controller.repeat();
  }

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

  @override
  Widget build(BuildContext context) {
    return CustomPaint(
      size: Size(100, 100),
      painter: CurveBoxPainter(_controller, _angleAnimation), // 背景
    );
  }
}

class CurveBoxPainter extends CustomPainter {
  final Animation<double> repaint; //
  Animation<double> angleAnimation;

  Paint _paint = Paint();

  CurveBoxPainter(this.repaint, this.angleAnimation) : super(repaint: repaint) {}

  @override
  void paint(Canvas canvas, Size size) {
    canvas.clipRect(Offset.zero & size);
    canvas.translate(size.width / 2, size.height / 2);
    _drawRing(canvas, size);
    _drawRedCircle(canvas, size);
    _drawGreenCircle(canvas, size);
  }

  //绘制环
  void _drawRing(Canvas canvas, Size size) {
    final double strokeWidth = 5;
    _paint
      ..color = Colors.blue
      ..style = PaintingStyle.stroke
      ..strokeWidth = strokeWidth;
    canvas.drawCircle(Offset.zero, size.width / 2 - strokeWidth, _paint);
  }

  // 绘制红球
  void _drawRedCircle(Canvas canvas, Size size) {
    canvas.save();
    canvas.rotate(angleAnimation.value * 2 * pi);
    _paint
      ..color = Colors.red
      ..style = PaintingStyle.fill;
    canvas.drawCircle(
        Offset.zero.translate(0, -(size.width / 2 - 5)), 5, _paint);
    canvas.restore();
  }

  // 绘制绿球
  void _drawGreenCircle(Canvas canvas, Size size) {
    canvas.save();
    canvas.translate(0,angleAnimation.value * (size.height-10));
    _paint
      ..color = Colors.green
      ..style = PaintingStyle.fill;
    canvas.drawCircle(
        Offset.zero.translate(0, -(size.width / 2 - 5)), 5, _paint);
    canvas.restore();
  }

  @override
  bool shouldRepaint(covariant CurveBoxPainter oldDelegate) =>
      oldDelegate.repaint != repaint;
}

二、动画器的方法

1.forward和reverse方法

|— forward({double from}) 执行运动直到上界。可指定初始值。(执行完毕就会停止)
|— reverse({double from}) 执行运动到下界。可以指定初始值。(执行完毕之后就会停止)

2.repeat重复执行

repeat
	|--- double?min,
	|--- double? max
	|--- bool reverse=false // 是否反转
	|--- Duration? period // 周期

3. fling方法

fling也就是猛冲。可以给一个速度。默认为1

4. stop和reset

stop方法是让_ticker停止。这样动画也就停止了。可以传入一个bool值。reset方法也很简单。就是将当前值设置为下界。

void stop({bool canceld=true}){
	_simukation=null;
	_lastElapsedDuration=null;
	_ticker.stop(canceld:canceled)
}

void reset(){
	value=lowerBound;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值