github地址:https://github.com/LaoMengFlutter/flutter-do
我个人认为最复杂的,也是花费时间最长的动画效果
放慢来看,是一个3x3的矩形,从左下角开始,每一斜排依次缩小,再还原的过程,下面就一步步实现,先绘制一个矩形:
class Square extends StatelessWidget {
final Color color;
const Square({Key? key,required this.color}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
color: color,
);
}
}
绘制3x3的矩形,并给每一个矩形添加 「ScaleTransition」 ,用于后面实现缩放
@override
Widget build(BuildContext context) {
return SizedBox.fromSize(
size: Size.square(widget.size),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_square(_anim3, 0),
_square(_anim4, 1),
_square(_anim5, 2),
],
),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_square(_anim2, 3),
_square(_anim3, 4),
_square(_anim4, 5),
],
),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_square(_anim1, 6),
_square(_anim2, 7),
_square(_anim3, 8),
],
),
],
),
);
}
Widget _square(Animation<double> animation, int index) {
return ScaleTransition(
scale: animation,
child: SizedBox.fromSize(
size: Size.square(widget.size / 3.0),
child: Square(
color: widget.color,
)),
);
}
重点来了,为什么需要5个 「Animation」 呢?因为共有5个斜排,同一个斜排使用一个Animation,如图:
其中1-5数字代表代码中的 _anim1, _anim2, _anim3, _anim4, _anim5,动画的效果都是依次缩小,再还原的过程,但1-2-3-4-5依次完成,并不是同时完成,代码如下:
_anim1 = TweenSequence([
TweenSequenceItem(tween: Tween(begin: 1.0, end: 0.0), weight: 50),
TweenSequenceItem(tween: Tween(begin: 0.0, end: 1.0), weight: 50),
]).animate(CurvedAnimation(
parent: _controller, curve: Interval(0.1, 0.6, curve: widget.curve)));
_anim2 = TweenSequence([
TweenSequenceItem(tween: Tween(begin: 1.0, end: 0.0), weight: 50),
TweenSequenceItem(tween: Tween(begin: 0.0, end: 1.0), weight: 50),
]).animate(CurvedAnimation(
parent: _controller, curve: Interval(0.2, 0.7, curve: widget.curve)));
_anim3 = TweenSequence([
TweenSequenceItem(tween: Tween(begin: 1.0, end: 0.0), weight: 50),
TweenSequenceItem(tween: Tween(begin: 0.0, end: 1.0), weight: 50),
]).animate(CurvedAnimation(
parent: _controller, curve: Interval(0.3, 0.8, curve: widget.curve)));
_anim4 = TweenSequence([
TweenSequenceItem(tween: Tween(begin: 1.0, end: 0.0), weight: 50),
TweenSequenceItem(tween: Tween(begin: 0.0, end: 1.0), weight: 50),
]).animate(CurvedAnimation(
parent: _controller, curve: Interval(0.4, 0.9, curve: widget.curve)));
_anim5 = TweenSequence([
TweenSequenceItem(tween: Tween(begin: 1.0, end: 0.0), weight: 50),
TweenSequenceItem(tween: Tween(begin: 0.0, end: 1.0), weight: 50),
]).animate(CurvedAnimation(
parent: _controller, curve: Interval(0.5, 1.0, curve: widget.curve)));
难点解决了,下面是完整的代码:
import 'package:flutter/material.dart';
///
/// desc:
///
class SquareGridScaleLoading extends StatefulWidget {
final double size;
final Duration duration;
final Curve curve;
final Color color;
const SquareGridScaleLoading(
{Key? key,
this.color = Colors.white,
this.size = 48.0,
this.duration = const Duration(milliseconds: 1500),
this.curve = Curves.linear})
: super(key: key);
@override
_SquareGridScaleLoadingState createState() => _SquareGridScaleLoadingState();
}
class _SquareGridScaleLoadingState extends State<SquareGridScaleLoading>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _anim1, _anim2, _anim3, _anim4, _anim5;
@override
void initState() {
_controller = AnimationController(vsync: this, duration: widget.duration)
..repeat();
_anim1 = TweenSequence([
TweenSequenceItem(tween: Tween(begin: 1.0, end: 0.0), weight: 50),
TweenSequenceItem(tween: Tween(begin: 0.0, end: 1.0), weight: 50),
]).animate(CurvedAnimation(
parent: _controller, curve: Interval(0.1, 0.6, curve: widget.curve)));
_anim2 = TweenSequence([
TweenSequenceItem(tween: Tween(begin: 1.0, end: 0.0), weight: 50),
TweenSequenceItem(tween: Tween(begin: 0.0, end: 1.0), weight: 50),
]).animate(CurvedAnimation(
parent: _controller, curve: Interval(0.2, 0.7, curve: widget.curve)));
_anim3 = TweenSequence([
TweenSequenceItem(tween: Tween(begin: 1.0, end: 0.0), weight: 50),
TweenSequenceItem(tween: Tween(begin: 0.0, end: 1.0), weight: 50),
]).animate(CurvedAnimation(
parent: _controller, curve: Interval(0.3, 0.8, curve: widget.curve)));
_anim4 = TweenSequence([
TweenSequenceItem(tween: Tween(begin: 1.0, end: 0.0), weight: 50),
TweenSequenceItem(tween: Tween(begin: 0.0, end: 1.0), weight: 50),
]).animate(CurvedAnimation(
parent: _controller, curve: Interval(0.4, 0.9, curve: widget.curve)));
_anim5 = TweenSequence([
TweenSequenceItem(tween: Tween(begin: 1.0, end: 0.0), weight: 50),
TweenSequenceItem(tween: Tween(begin: 0.0, end: 1.0), weight: 50),
]).animate(CurvedAnimation(
parent: _controller, curve: Interval(0.5, 1.0, curve: widget.curve)));
super.initState();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return SizedBox.fromSize(
size: Size.square(widget.size),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_square(_anim3, 0),
_square(_anim4, 1),
_square(_anim5, 2),
],
),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_square(_anim2, 3),
_square(_anim3, 4),
_square(_anim4, 5),
],
),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_square(_anim1, 6),
_square(_anim2, 7),
_square(_anim3, 8),
],
),
],
),
);
}
Widget _square(Animation<double> animation, int index) {
return ScaleTransition(
scale: animation,
child: SizedBox.fromSize(
size: Size.square(widget.size / 3.0),
child: Square(
color: widget.color,
)),
);
}
}
class Square extends StatelessWidget {
final Color color;
const Square({Key? key,required this.color}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
color: color,
);
}
}
最终的效果如下: