最近寫(xiě)了一些flutter的小動(dòng)畫(huà),在這里也寫(xiě)幾個(gè)篇章介紹下flutter的動(dòng)畫(huà)的實(shí)現(xiàn)备徐,先實(shí)現(xiàn)個(gè)簡(jiǎn)單的幀動(dòng)畫(huà)淮阐,舉例美團(tuán)的加載動(dòng)畫(huà)就是幀動(dòng)畫(huà)的實(shí)現(xiàn),那換flutter的怎么實(shí)現(xiàn)呢望侈,一起看看
主要的類實(shí)現(xiàn)FrameAnimationImage
class FrameAnimationImage extends StatefulWidget {
final List<String> _assetList;
final double width;
final double height;
bool start = true;
int interval = 200;
FrameAnimationImage(Key key, this._assetList,
{this.width, this.height, this.interval, this.start})
: super(key: key);
@override
State<StatefulWidget> createState() {
return FrameAnimationImageState();
}
}
class FrameAnimationImageState extends State<FrameAnimationImage>
with SingleTickerProviderStateMixin {
// 動(dòng)畫(huà)控制
Animation<double> _animation;
AnimationController _controller;
int interval = 200;
@override
void initState() {
super.initState();
if (widget.interval != null) {
interval = widget.interval;
}
final int imageCount = widget._assetList.length;
final int maxTime = interval * imageCount;
// 啟動(dòng)動(dòng)畫(huà)controller
_controller = new AnimationController(
duration: Duration(milliseconds: maxTime), vsync: this);
_controller.addStatusListener((AnimationStatus status) {
if (status == AnimationStatus.completed) {
_controller.forward(from: 0.0); // 完成后重新開(kāi)始
}
});
_animation = new Tween<double>(begin: 0, end: imageCount.toDouble())
.animate(_controller)
..addListener(() {
setState(() {
// the state that has changed here is the animation object’s value
});
});
if (widget.start) {
_controller.forward();
}
}
void startAnimation() => _controller.forward();
void stopAnimation() => _controller.stop();
void reStartAnimation(){
_controller.reset();
_controller.forward();
}
@override
void didUpdateWidget(FrameAnimationImage oldWidget) {
// TODO: implement didUpdateWidget
super.didUpdateWidget(oldWidget);
print("didUpdateWidget called");
if (widget.start) {
_controller.forward();
}
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
int ix = _animation.value.floor() % widget._assetList.length;
List<Widget> images = [];
// 把所有圖片都加載進(jìn)內(nèi)容,否則每一幀加載時(shí)會(huì)卡頓
for (int i = 0; i < widget._assetList.length; ++i) {
if (i != ix) {
images.add(Image.asset(
ImageUtils.getImagePath( widget._assetList[i]),///ImageUtils只是一個(gè)簡(jiǎn)單出來(lái)圖片格式的方法
width: 0,
height: 0,
));
}
}
images.add(Image.asset(
ImageUtils.getImagePath(widget._assetList[ix]),//
width: widget.width,
height: widget.height,
));
return Stack(alignment: AlignmentDirectional.center, children: images);
}
}
//class ImageUtils {
// static String getImagePath(String name, {String format: 'png'}) {
// return 'assets/images/$name.$format';
// }
//
// static ImageProvider getImageProvider(String imageUrl,
// {String holderImg: "none"}) {
// if (TextUtil.isEmpty(imageUrl)) {
// return AssetImage(getImagePath(holderImg));
// }
// return CachedNetworkImageProvider(imageUrl);
// }
//}
這個(gè)類的實(shí)現(xiàn)也比較好理解的勋桶,通過(guò)監(jiān)聽(tīng)AnimationStatus 動(dòng)畫(huà)的狀態(tài)脱衙,對(duì)動(dòng)畫(huà)實(shí)現(xiàn)控制。下面看下實(shí)現(xiàn)示例.
準(zhǔn)備好圖片:
go1.png
go2.png
go3.png
go4.png
class Frame extends StatelessWidget {
bool b = false;
final List<String> list = [
'go1',
'go2',
'go3',
'go4',
];
final GlobalKey<FrameAnimationImageState> _cotroller = new GlobalKey<FrameAnimationImageState>();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('幀動(dòng)畫(huà)'),
centerTitle: true,
),
body: Column(
children: <Widget>[
Center(
child: GestureDetector(
onTap: () {
if (b) {
_cotroller.currentState.reStartAnimation();
} else {
_cotroller.currentState.startAnimation();
}
b = !b;
},
child: FrameAnimationImage(_cotroller, list,
width: 220, height: 200, interval: 50, start: false),
),
),
RaisedButton(
onPressed: (){
_cotroller.currentState.stopAnimation();
},
child: Text("結(jié)束"),
)
],
)
);
}
}
將圖片上去例驹,運(yùn)行捐韩、就可以看見(jiàn)小鹿跑動(dòng)的動(dòng)畫(huà)啦。
很簡(jiǎn)單是不是鹃锈,幀動(dòng)畫(huà)就這樣吧荤胁,要是控制時(shí)間什么的自己添加修改就好了,還有注意幀動(dòng)畫(huà)圖片的大小喔屎债。