Flutter繪製-13-動畫專項-多種多樣的Tween

天色將變發表於2021-05-14

檢視目錄-->

Flutter內建了很多的Tween,下面一一看下:

ColorTween

可以設定顏色漸變,begin顏色,end顏色,中間過渡。

  • 設定顏色過渡,初始顏色綠色,目標顏色棕色,Tween colorTween = new ColorTween(begin: Colors.green,end:Colors.orange);
    • 方式一:通過colorTween.evaluate(_controller)來獲取漸變的顏色
    • 方式二:通過animate
      • Animation _animation
      • new ColorTween(begin: Colors.green, end: Colors.orange);
      • _animation = colorTween.animate(_controller);
      • color: _animation.value

5.gif

程式碼如下:

import 'package:flutter/material.dart';

class Test10ColorTween extends StatefulWidget {
  @override
  _State createState() => _State();
}

class _State extends State<Test10ColorTween>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;
  Tween colorTween = new ColorTween(begin: Colors.green, end: Colors.orange);
  Animation<Color> _animationColor;
  @override
  void initState() {
    super.initState();
    _controller = new AnimationController(
        vsync: this, duration: const Duration(milliseconds: 5000));
    _animationColor = colorTween.animate(_controller);
    _controller.addListener(() {
      setState(() {});
    });
    // 動畫開始執行
    _controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("ColorTween"),
        centerTitle: true,
      ),
      body: Center(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              width: 200,
              height: 200,
              margin: EdgeInsets.all(10),
              color: colorTween.evaluate(_controller),
            ),
            Container(
              width: 200,
              height: 200,
              margin: EdgeInsets.all(10),
              color: _animationColor.value,
            ),
            Text("ColorTween",
                style: TextStyle(
                  fontSize: 14,
                )),
          ],
        ),
      ),
    );
  }

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



複製程式碼
IntTween

直接new Tween()時,begin 和 end是double的,IntTween的begin和end是int型的。

Tween sizeTween = new IntTween(begin: 0,end: 200);

print("${sizeTween.evaluate(_controller)}");
複製程式碼
  • 通過evaluate,列印的值全是int的。
  • 通過animate.value獲取到的值都是int的。

1.gif

程式碼如下:

import 'package:flutter/material.dart';

class Test09IntTween extends StatefulWidget {
  @override
  _State createState() => _State();
}

class _State extends State<Test09IntTween> with SingleTickerProviderStateMixin {
  AnimationController _controller;
  Tween intTween = new IntTween(begin: 0, end: 200);
  Animation<int> _animationInt;

  @override
  void initState() {
    super.initState();
    _controller = new AnimationController(
        vsync: this, duration: const Duration(milliseconds: 6000));
    _animationInt = intTween.animate(_controller);
    _controller.addListener(() {
      setState(() {});
    });
    // 動畫開始執行
    _controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("IntTween"),
        centerTitle: true,
      ),
      body: Center(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              width: _animationInt.value.toDouble(),
              height: _animationInt.value.toDouble(),
              margin: EdgeInsets.all(10),
              color: Colors.black12,
            ),
            Text("IntTween,_animationInt.value=${_animationInt.value}",
                style: TextStyle(
                  fontSize: 14,
                )),
          ],
        ),
      ),
    );
  }

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

複製程式碼
SizeTween

基於Size的過渡變化,其實是size內兩個值的變化。

Tween sizeTween = new SizeTween(begin: Size(0.0,0.0),end: Size(100.0,100.0));
Animation<Size> animation = sizeTween.animate(_controller);
Size size = animation.value;
複製程式碼
  • 注意Animation animation = sizeTween.animate(_controller); 泛型是Size

效果:

2.gif

程式碼如下:

import 'package:flutter/material.dart';

class Test11SizeTween extends StatefulWidget {
  @override
  _State createState() => _State();
}

class _State extends State<Test11SizeTween>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;
  Tween sizeTween =
      new SizeTween(begin: Size(0.0, 0.0), end: Size(100.0, 200.0));
  Animation<Size> _animationSize;

  @override
  void initState() {
    super.initState();
    _controller = new AnimationController(
        vsync: this, duration: const Duration(milliseconds: 5000));
    _animationSize = sizeTween.animate(_controller);
    _controller.addListener(() {
      setState(() {});
    });
    // 動畫開始執行
    _controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("SizeTween"),
        centerTitle: true,
      ),
      body: Center(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              width: _animationSize.value.width,
              height: _animationSize.value.height,
              margin: EdgeInsets.all(10),
              color: Colors.black12,
            ),
            Container(
              width: 300,
              child: Text("SizeTween.size.width=${_animationSize.value.width}",
                  style: TextStyle(
                    fontSize: 14,
                  )),
            ),
            Container(
              width: 300,
              child:
                  Text("SizeTween.size.height=${_animationSize.value.height}",
                      style: TextStyle(
                        fontSize: 14,
                      )),
            )
          ],
        ),
      ),
    );
  }

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

複製程式碼
RectTween

基於Rect矩形的過渡變化

Tween rectTween = new RectTween(begin: Rect.fromLTWH(0, 0, 0, 0),end: Rect.fromLTWH(100, 100, 100, 100));
Animation<Rect> animation = rectTween.animate(_controller);
Rect rect = animation.value;
複製程式碼

效果:

3.gif

程式碼如下:

import 'package:flutter/material.dart';

class Test12RectTween extends StatefulWidget {
  @override
  _State createState() => _State();
}

class _State extends State<Test12RectTween>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;
  Tween rectTween = new RectTween(
      begin: Rect.fromLTWH(0, 0, 0, 0), end: Rect.fromLTWH(100, 100, 100, 100));
  Animation<Rect> _animationRect;

  @override
  void initState() {
    super.initState();
    _controller = new AnimationController(
        vsync: this, duration: const Duration(milliseconds: 5000));
    _animationRect = rectTween.animate(_controller);
    _controller.addListener(() {
      setState(() {});
    });
    // 動畫開始執行
    _controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("RectTween"),
        centerTitle: true,
      ),
      body: Center(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              width: 200,
              height: 200,
              margin: EdgeInsets.all(10),
              color: Colors.black12,
              child: CustomPaint(
                painter: _MyRectPainter(_animationRect),
              ),
            ),
            Text("RectTween",
                style: TextStyle(
                  fontSize: 14,
                )),
          ],
        ),
      ),
    );
  }

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

class _MyRectPainter extends CustomPainter {
  Animation<Rect> animation;

  _MyRectPainter(this.animation) : super(repaint: animation);

  @override
  void paint(Canvas canvas, Size size) {
    Paint paint = Paint()
      ..color = Colors.red
      ..strokeWidth = 1
      ..style = PaintingStyle.stroke;
    canvas.drawRect(animation.value, paint);
  }

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

  void translateToCenter(Canvas canvas, Size size) {
    canvas.translate(size.width / 2, size.height / 2);
  }
}

複製程式碼
StepTween

每次返回插值的floor,從double變為了int。

Tween stepTween = new StepTween(begin: 0,end: 100);
Animation<int> animation = stepTween.animate(_controller);
int value = animation.value;
複製程式碼

效果:

4.gif

程式碼如下:

import 'package:flutter/material.dart';

class Test13StepTween extends StatefulWidget {
  @override
  _State createState() => _State();
}

class _State extends State<Test13StepTween>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;
  Tween stepTween = new StepTween(begin: 0, end: 100);
  Animation<int> _animationStep;

  @override
  void initState() {
    super.initState();
    _controller = new AnimationController(
        vsync: this, duration: const Duration(milliseconds: 6000));
    _animationStep = stepTween.animate(_controller);
    _controller.addListener(() {
      setState(() {});
    });
    // 動畫開始執行
    _controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("StepTween"),
        centerTitle: true,
      ),
      body: Center(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              width: 200,
              height: 200,
              margin: EdgeInsets.all(10),
              color: Colors.black12,
              child: CustomPaint(
                painter: _MyStepPainter(_animationStep),
              ),
            ),
            Text("StepTween.value=${_animationStep.value}",
                style: TextStyle(
                  fontSize: 14,
                )),
          ],
        ),
      ),
    );
  }

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

class _MyStepPainter extends CustomPainter {
  Animation<int> animation;

  _MyStepPainter(this.animation) : super(repaint: animation);

  @override
  void paint(Canvas canvas, Size size) {
    Paint paint = Paint()
      ..color = Colors.red
      ..strokeWidth = 1
      ..style = PaintingStyle.stroke;
    canvas.drawRect(
        Rect.fromLTWH(
            0, 0, animation.value.toDouble(), animation.value.toDouble()),
        paint);
  }

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

  void translateToCenter(Canvas canvas, Size size) {
    canvas.translate(size.width / 2, size.height / 2);
  }
}

複製程式碼
ConstantTween

每次返回插常量值,建立時傳入什麼型別的值,就獲取什麼型別的值

Tween constantTween = new ConstantTween(100.0);
Animation<int> animation = constantTween.animate(_controller);
int value = animation.value;
複製程式碼

效果:

5.gif

程式碼如下:

import 'package:flutter/material.dart';

class Test14ConstantTween extends StatefulWidget {
  @override
  _State createState() => _State();
}

class _State extends State<Test14ConstantTween>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;
  Tween constantTween = new ConstantTween<String>("ConstantTween");
  Animation<String> _animationConstant;

  @override
  void initState() {
    super.initState();
    _controller = new AnimationController(
        vsync: this, duration: const Duration(milliseconds: 5000));

    _animationConstant = constantTween.animate(_controller);
    _controller.addListener(() {
      setState(() {});
    });
    // 動畫開始執行
    _controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("ConstantTween"),
        centerTitle: true,
      ),
      body: Center(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              width: 200,
              height: 200,
              margin: EdgeInsets.all(10),
              color: Colors.black12,
              child: Center(
                child: Text(_animationConstant.value,
                    style: TextStyle(fontSize: 14, color: Colors.red)),
              ),
            ),
            Text("ConstantTween",
                style: TextStyle(
                  fontSize: 14,
                )),
          ],
        ),
      ),
    );
  }

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

複製程式碼
CurveTween

注意CurveTween extends Animatable,不是Tween的子類。用給定的curve將_controller.value進行了轉換。

CurveTween curveTween = new CurveTween(curve:Curves.easeInToLinear);
Animation<double> animation = curveTween.animate(_controller);
double value = animation.value;
複製程式碼
  • animation.value值在[0,1]之間

效果:

6.gif

程式碼如下:

import 'package:flutter/material.dart';

class Test15CurveTween extends StatefulWidget {
  @override
  _State createState() => _State();
}

class _State extends State<Test15CurveTween>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;
  CurveTween curveTween = new CurveTween(curve: Curves.bounceInOut);
  Animation<double> _animationCurve;

  @override
  void initState() {
    super.initState();
    _controller = new AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 6000),
    );
    _animationCurve = curveTween.animate(_controller);
    _controller.addListener(() {
      setState(() {});
    });
    // 動畫開始執行
    _controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("CurveTween"),
        centerTitle: true,
      ),
      body: Center(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              width: 200,
              height: 200,
              margin: EdgeInsets.all(10),
              color: Colors.black12,
              child: CustomPaint(
                painter: _MyCurvePainter(_animationCurve),
              ),
            ),
            Container(
              width: 300,
              child: Text("CurveTween.value=${_animationCurve.value}",
                  style: TextStyle(
                    fontSize: 14,
                  )),
            )
          ],
        ),
      ),
    );
  }

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

class _MyCurvePainter extends CustomPainter {
  Animation<double> animation;

  _MyCurvePainter(this.animation) : super(repaint: animation);

  @override
  void paint(Canvas canvas, Size size) {
    translateToCenter(canvas, size);
    Paint paint = Paint()
      ..color = Colors.red
      ..style = PaintingStyle.fill;
    canvas.drawCircle(
        Offset(animation.value * 100, animation.value * 100), 10, paint);
  }

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

  void translateToCenter(Canvas canvas, Size size) {
    canvas.translate(size.width / 2, size.height / 2);
  }
}

複製程式碼
AlignmentTween

基於Alignment屬性的過渡,比如Container的child從topleft移動到bottomRight.

看下效果:

7.gif

程式碼如下:

import 'package:flutter/material.dart';

class Test16AlignmentTween extends StatefulWidget {
  @override
  _State createState() => _State();
}

class _State extends State<Test16AlignmentTween>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;
  Tween _tween =
      new AlignmentTween(begin: Alignment.topLeft, end: Alignment.bottomRight);
  Animation<Alignment> _animation;
  @override
  void initState() {
    super.initState();
    _controller = new AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 6000),
    );
    _animation = _tween.animate(_controller);
    _controller.addListener(() {
      setState(() {});
    });
    // 動畫開始執行
    _controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("AlignmentTween"),
        centerTitle: true,
      ),
      body: Center(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              width: 400,
              height: 400,
              alignment: _animation.value,
              margin: EdgeInsets.all(10),
              color: Colors.black12,
              child: Container(
                width: 100,
                height: 100,
                color: Colors.orange,
              ),
            ),
          ],
        ),
      ),
    );
  }

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

複製程式碼
AlignmentGeometryTween

與AlignmentTween類似效果。 效果:

8.gif

程式碼如下:

import 'package:flutter/material.dart';

class Test17AlignmentGeometryTween extends StatefulWidget {
  @override
  _State createState() => _State();
}

class _State extends State<Test17AlignmentGeometryTween>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;
  Tween _tween = new AlignmentGeometryTween(
      begin: AlignmentDirectional.topCenter,
      end: AlignmentDirectional.centerEnd);
  Animation<AlignmentGeometry> _animation;
  @override
  void initState() {
    super.initState();
    _controller = new AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 6000),
    );
    _animation = _tween.animate(_controller);
    _controller.addListener(() {
      setState(() {});
    });
    // 動畫開始執行
    _controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("AlignmentGeometryTween"),
        centerTitle: true,
      ),
      body: Center(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              width: 400,
              height: 400,
              margin: EdgeInsets.all(10),
              color: Colors.black12,
              alignment: _animation.value,
              child: Container(
                width: 100,
                height: 100,
                color: Colors.orange,
              ),
            ),
          ],
        ),
      ),
    );
  }

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

複製程式碼
BorderRadiusTween

基於BorderRadius屬性的過渡。

效果如下:

9.gif

程式碼如下:

import 'package:flutter/material.dart';

class Test18BorderRadiusTween extends StatefulWidget {
  @override
  _State createState() => _State();
}

class _State extends State<Test18BorderRadiusTween>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;
  Tween _tween = new BorderRadiusTween(
      begin: BorderRadius.circular(0), end: BorderRadius.circular(200));
  Animation<BorderRadius> _animation;
  @override
  void initState() {
    super.initState();
    _controller = new AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 6000),
    );
    _animation = _tween.animate(_controller);
    _controller.addListener(() {
      setState(() {});
    });
    // 動畫開始執行
    _controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("BorderRadiusTween"),
        centerTitle: true,
      ),
      body: Center(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              width: 400,
              height: 400,
              margin: EdgeInsets.all(10),
              decoration: BoxDecoration(borderRadius: _animation.value,color: Colors.orangeAccent),
            ),
          ],
        ),
      ),
    );
  }

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

複製程式碼
BorderTween

基於Border屬性的過渡。

效果如下:

10.gif

程式碼如下:

import 'package:flutter/material.dart';

class Test19BorderTween extends StatefulWidget {
  @override
  _State createState() => _State();
}

class _State extends State<Test19BorderTween>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;
  Tween _tween = new BorderTween(
      begin: Border(top: BorderSide(width: 0, color: Colors.red)),
      end: Border(
          top: BorderSide(width: 50, color: Colors.green),
          bottom: BorderSide(width: 50, color: Colors.blueAccent)));
  Animation<Border> _animation;
  @override
  void initState() {
    super.initState();
    _controller = new AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 6000),
    );
    _animation = _tween.animate(_controller);
    _controller.addListener(() {
      setState(() {});
    });
    // 動畫開始執行
    _controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("BorderTween"),
        centerTitle: true,
      ),
      body: Center(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              width: 400,
              height: 400,
              margin: EdgeInsets.all(10),
              decoration: BoxDecoration(
                  border: _animation.value, color: Colors.orangeAccent),
            ),
          ],
        ),
      ),
    );
  }

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

複製程式碼
ShapeBorderTween

基於ShapeBorder屬性的過渡。

效果如下:

11.gif

程式碼如下:

import 'package:flutter/material.dart';

class Test20ShapeBorderTween extends StatefulWidget {
  @override
  _State createState() => _State();
}

class _State extends State<Test20ShapeBorderTween>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;
  Tween _tween = new ShapeBorderTween(
      begin: RoundedRectangleBorder(
          side: BorderSide(width: 0, color: Colors.red),
          borderRadius: BorderRadius.circular(0)),
      end: RoundedRectangleBorder(
          side: BorderSide(width: 50, color: Colors.green),
          borderRadius: BorderRadius.circular(200)));
  Animation<ShapeBorder> _animation;
  @override
  void initState() {
    super.initState();
    _controller = new AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 6000),
    );
    _animation = _tween.animate(_controller);
    _controller.addListener(() {
      setState(() {});
    });
    // 動畫開始執行
    _controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("ShapeBorderTween"),
        centerTitle: true,
      ),
      body: Center(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              width: 400,
              height: 400,
              margin: EdgeInsets.all(10),
              decoration: ShapeDecoration(shape: _animation.value,color: Colors.orangeAccent),
            ),
          ],
        ),
      ),
    );
  }

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

複製程式碼
DecorationTween

基於Decoration屬性的過渡。

效果如下:

12.gif

程式碼如下:

import 'package:flutter/material.dart';

class Test21DecorationTween extends StatefulWidget {
  @override
  _State createState() => _State();
}

class _State extends State<Test21DecorationTween>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;
  Tween _tween = new DecorationTween(
      begin: BoxDecoration(
          color: Colors.red,
          // borderRadius: BorderRadius.circular(0),
          border: Border(top: BorderSide(color: Colors.red, width: 0)),
          // shape: BoxShape.rectangle,
          gradient: LinearGradient(
              colors: [Colors.red, Colors.green, Colors.blueAccent])),
      end: BoxDecoration(
          color: Colors.orangeAccent,
          // borderRadius: BorderRadius.circular(200),
          border: Border(top: BorderSide(color: Colors.black, width: 50)),
          // shape: BoxShape.circle,
          gradient: LinearGradient(colors: [
            Colors.black12,
            Colors.blueAccent,
            Colors.yellowAccent
          ])));

  Animation<Decoration> _animation;
  @override
  void initState() {
    super.initState();
    _controller = new AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 6000),
    );
    _animation = _tween.animate(_controller);
    _controller.addListener(() {
      setState(() {});
    });
    // 動畫開始執行
    _controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("DecorationTween"),
        centerTitle: true,
      ),
      body: Center(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              width: 400,
              height: 400,
              margin: EdgeInsets.all(10),
              decoration: _animation.value,
            ),
          ],
        ),
      ),
    );
  }

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

複製程式碼
BoxConstraintsTween

基於BoxConstraints屬性的過渡。

效果如下:

13.gif

程式碼如下:

import 'package:flutter/material.dart';

class Test22BoxConstraintsTween extends StatefulWidget {
  @override
  _State createState() => _State();
}

class _State extends State<Test22BoxConstraintsTween>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;

  Tween _tween = new BoxConstraintsTween(
      begin: BoxConstraints(maxWidth: 0, minHeight: 0),
      end: BoxConstraints(maxWidth: 200, minHeight: 200));

  Animation<BoxConstraints> _animation;
  @override
  void initState() {
    super.initState();
    _controller = new AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 6000),
    );
    _animation = _tween.animate(_controller);
    _controller.addListener(() {
      setState(() {});
    });
    // 動畫開始執行
    _controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("BoxConstraintsTween"),
        centerTitle: true,
      ),
      body: Center(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              margin: EdgeInsets.all(10),
              color: Colors.orangeAccent,
              constraints: _animation.value,
            ),
          ],
        ),
      ),
    );
  }

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

複製程式碼
EdgeInsetsTween

基於padding 或 margin等需要EdgeInsets控制的屬性的過渡。

效果如下:

14.gif

程式碼如下:

import 'package:flutter/material.dart';

class Test23EdgeInsetsTween extends StatefulWidget {
  @override
  _State createState() => _State();
}

class _State extends State<Test23EdgeInsetsTween>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;

  Tween _tween = new EdgeInsetsTween(
      begin: EdgeInsets.only(left: 0, top: 0),
      end: EdgeInsets.only(left: 100, top: 50));
  Animation<EdgeInsets> _animation;
  @override
  void initState() {
    super.initState();
    _controller = new AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 6000),
    );
    _animation = _tween.animate(_controller);
    _controller.addListener(() {
      setState(() {});
    });
    // 動畫開始執行
    _controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("EdgeInsetsTween"),
        centerTitle: true,
      ),
      body: Center(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              width: 200,
              height: 200,
              padding: _animation.value,
              margin: EdgeInsets.all(10),
              color: Colors.orangeAccent,
              child: Text("pushing by padding"),
            ),
          ],
        ),
      ),
    );
  }

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

複製程式碼
EdgeInsetsGeometryTween

基於padding 或 margin等需要EdgeInsetsGeometry控制的屬性的過渡。EdgeInsetsGeometry是EdgeInsets的父類。效果幾乎一樣。

效果如下:

14.gif

程式碼如下:

import 'package:flutter/material.dart';

class Test24EdgeInsetsGeometryTween extends StatefulWidget {
  @override
  _State createState() => _State();
}

class _State extends State<Test24EdgeInsetsGeometryTween>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;

  Tween _tween = new EdgeInsetsGeometryTween(
      begin: EdgeInsets.only(left: 0, top: 0),
      end: EdgeInsets.only(left: 100, top: 50));

  Animation<EdgeInsetsGeometry> _animation;
  @override
  void initState() {
    super.initState();
    _controller = new AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 6000),
    );
    _animation = _tween.animate(_controller);
    _controller.addListener(() {
      setState(() {});
    });
    // 動畫開始執行
    _controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("EdgeInsetsGeometryTween"),
        centerTitle: true,
      ),
      body: Center(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              width: 200,
              height: 200,
              padding: _animation.value,
              margin: EdgeInsets.all(10),
              color: Colors.orangeAccent,
              child: Text("pushing by padding"),
            ),
          ],
        ),
      ),
    );
  }

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

複製程式碼
TextStyleTween

基於Text的style屬性的過渡,TextStyle的所有屬性都可以漸變。

效果如下:

1.gif

程式碼如下:

import 'package:flutter/material.dart';

class Test25TextStyleTween extends StatefulWidget {
  @override
  _State createState() => _State();
}

class _State extends State<Test25TextStyleTween>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;

  Tween _tween = new TextStyleTween(
      begin: TextStyle(color: Colors.red,fontSize: 10),
      end: TextStyle(color: Colors.blue,fontSize: 40));
  Animation<TextStyle> _animation;
  @override
  void initState() {
    super.initState();
    _controller = new AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 6000),
    );
    _animation = _tween.animate(_controller);
    _controller.addListener(() {
      setState(() {});
    });
    // 動畫開始執行
    _controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("TextStyleTween"),
        centerTitle: true,
      ),
      body: Center(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              width: 200,
              height: 200,
              margin: EdgeInsets.all(10),
              color: Colors.orangeAccent,
              alignment: Alignment.center,
              child: Text("TextStyle changing",style: _animation.value,),
            ),
          ],
        ),
      ),
    );
  }

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

複製程式碼
Matrix4Tween

基於四階矩陣的漸變,以canvas的transform為例。

效果:

1.gif

程式碼如下:

import 'package:flutter/material.dart';

class Test26Matrix4Tween extends StatefulWidget {
  @override
  _State createState() => _State();
}

class _State extends State<Test26Matrix4Tween>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;

  Tween _tween = new Matrix4Tween(
      begin: Matrix4(
        1,0,0,0,
        0,1,0,0,
        0,0,1,0,
        0,0,0,1,
      ),
      end: Matrix4(
        1,0,0,0,
        0,1,0,0,
        0,0,1,0,
        100,0,0,1,// 延x平移100
      ));
  Animation<Matrix4> _animation;
  @override
  void initState() {
    super.initState();
    _controller = new AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 6000),
    );
    _animation = _tween.animate(_controller);
    _controller.addListener(() {
      setState(() {});
    });
    // 動畫開始執行
    _controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Matrix4Tween"),
        centerTitle: true,
      ),
      body: Center(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              width: 400,
              height: 400,
              margin: EdgeInsets.all(10),
              color: Colors.orangeAccent,
              alignment: Alignment.center,
              child: CustomPaint(
                size: Size(200,200),
                painter: _MyRectPainter(_animation),
              ),
            ),
          ],
        ),
      ),
    );
  }

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


class _MyRectPainter extends CustomPainter {
  Animation<Matrix4> animation;

  _MyRectPainter(this.animation) : super(repaint: animation);

  @override
  void paint(Canvas canvas, Size size) {
    translateToCenter(canvas, size);
    Paint paint = Paint()
      ..color = Colors.red
      ..strokeWidth = 1
      ..style = PaintingStyle.stroke;
    canvas.drawCircle(Offset.zero, 100, paint);
    canvas.transform(animation.value.storage);
    canvas.drawCircle(Offset.zero, 100, paint);
  }

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

  void translateToCenter(Canvas canvas, Size size) {
    canvas.translate(size.width / 2, size.height / 2);
  }
}
複製程式碼
Test27ThemeDataTween

可以定義主題漸變的Tween. 效果:

2.gif

程式碼:

import 'package:flutter/material.dart';

class Test27ThemeDataTween extends StatefulWidget {
  @override
  _State createState() => _State();
}

class _State extends State<Test27ThemeDataTween>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;

  Tween _tween = new ThemeDataTween(
      begin: ThemeData(primaryColor: Colors.blue),
      end:  ThemeData(primaryColor: Colors.green));
  Animation<ThemeData> _animation;
  @override
  void initState() {
    super.initState();
    _controller = new AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 6000),
    );
    _animation = _tween.animate(_controller);
    _controller.addListener(() {
      setState(() {});
    });
    // 動畫開始執行
    _controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return Theme(
      data: _animation.value,
      child: Scaffold(
        appBar: AppBar(
          title: Text("ThemeDataTween"),
          centerTitle: true,
        ),
        body: Center(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Container(
                width: 400,
                height: 400,
                margin: EdgeInsets.all(10),
                color: _animation.value.primaryColor,
              ),
            ],
          ),
        ),
      ),
    );
  }

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

複製程式碼
Test28RelativeRectTween

可以定義主題漸變的Tween. 效果:

3.gif

程式碼:

import 'package:flutter/material.dart';

class Test28RelativeRectTween extends StatefulWidget {
  @override
  _State createState() => _State();
}

class _State extends State<Test28RelativeRectTween>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;

  Tween _tween = new RelativeRectTween(
      begin: RelativeRect.fromLTRB(0, 0, 0, 0),
      end:  RelativeRect.fromLTRB(100, 100, 100, 100));
  Animation<RelativeRect> _animation;
  @override
  void initState() {
    super.initState();
    _controller = new AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 6000),
    );
    _animation = _tween.animate(_controller);
    _controller.addListener(() {
      setState(() {});
    });
    // 動畫開始執行
    _controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("RelativeRectTween"),
        centerTitle: true,
      ),
      body: Center(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              width: 400,
              height: 400,
              margin: EdgeInsets.all(10),
              color: Colors.orangeAccent,
              child: CustomPaint(
                painter: _MyRectPainter(_animation),
              ),
            ),
          ],
        ),
      ),
    );
  }

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


class _MyRectPainter extends CustomPainter {
  Animation<RelativeRect> animation;

  _MyRectPainter(this.animation) : super(repaint: animation);

  @override
  void paint(Canvas canvas, Size size) {
    Paint paint = Paint()
      ..color = Colors.red
      ..strokeWidth = 1
      ..style = PaintingStyle.stroke;
    Rect rect = Rect.fromLTWH(0, 0, size.width,size.height);
    canvas.drawRect(animation.value.toRect(rect), paint);
  }

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

  void translateToCenter(Canvas canvas, Size size) {
    canvas.translate(size.width / 2, size.height / 2);
  }
}
複製程式碼
Tween總結

flutter提供了有二十個左右的Tween,從基本型別到物件都有,但是有個明顯的特點:

  • 可量化,就算是物件,如Decoration,其實也是對其屬性的變化,都是可量化的。
  • 同一型別的變化,begin描述初始狀態,end描述結束狀態

親自動手試了這麼多Tween的效果,其實可以發現,本質都是對AnimationController插值[0,1]變化的封裝,我們自己也可以實現這些效果,只是flutter封裝後我們更便於使用。

相關文章