Flutter封裝組動(dòng)畫混合動(dòng)畫AnimatedGroup示例詳解
一、來源
項(xiàng)目中遇到混合動(dòng)畫的情況,每次實(shí)現(xiàn)都需要生命一堆屬性,讓代碼變得雜亂,難以維護(hù)。
參考 iOS 組動(dòng)畫 CAAimationGroup, 隨花半天時(shí)間封裝一個(gè)混合動(dòng)畫組件 AnimatedGroup。
此組件基于極簡(jiǎn)、高擴(kuò)展、高適用的封裝原則,基本滿足當(dāng)前項(xiàng)目開發(fā)。
二、AnimatedGroup使用示例:
//
// AnimatedGroupDemo.dart
// flutter_templet_project
//
// Created by shang on 12/6/21 5:52 PM.
// Copyright ? 12/6/21 shang. All rights reserved.
//
import 'package:flutter/material.dart';
import 'package:flutter_templet_project/basicWidget/animated_group.dart';
class AnimatedGroupDemo extends StatefulWidget {
AnimatedGroupDemo({ Key? key, this.title}) : super(key: key);
final String? title;
@override
_AnimatedGroupDemoState createState() => _AnimatedGroupDemoState();
}
class _AnimatedGroupDemoState extends State<AnimatedGroupDemo> {
GlobalKey<AnimatedGroupState> _globalKey = GlobalKey();
final _animations = <AnimatedGroupItemModel>[
AnimatedGroupItemModel(
tween: Tween<double>(begin: .0, end: 300.0,),
begin: 0.0,
end: 0.6
),
AnimatedGroupItemModel(
tween: ColorTween(begin: Colors.green, end: Colors.red,),
begin: 0.0,
end: 0.6
),
AnimatedGroupItemModel(
tween: Tween<EdgeInsets>(
begin: const EdgeInsets.only(left: .0),
end: const EdgeInsets.only(left: 100.0),
),
begin: 0.6,
end: 1.0
),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title ?? "$widget"),
),
body: Center(
child: Column(
children: [
ElevatedButton(
child: Text("start animation"),
onPressed: (){
_globalKey.currentState?.palyeAnimations(isRemovedOnCompletion: false);
},
),
Container(
width: 300,
height: 300,
child: AnimatedGroup(
key: _globalKey,
duration: Duration(milliseconds: 2000),
animations: _animations,
child: Text("AnimatedGroupWidget 混合動(dòng)畫", style: TextStyle(color: Colors.white, backgroundColor: Colors.green),),
builder: (BuildContext context, Widget? child, List<Animation<dynamic>> animations) {
final aHeight = animations[0];
final aColor = animations[1];
final aPadding = animations[2];
return Stack(
children: [
Container(
alignment: Alignment.bottomCenter,
padding: aPadding.value,
child: Container(
color: aColor.value,
width: 50.0,
height: aHeight.value,
),
),
Center(child: child!)
],
);
},
),
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.1),
border: Border.all(
color: Colors.black.withOpacity(0.5),
)
),
)
],
),
),
);
}
}
三、AnimatedGroup源碼
//
// AnimatedGroupDemo.dart
// flutter_templet_project
//
// Created by shang on 1/19/23 8:21 AM.
// Copyright ? 1/19/23 shang. All rights reserved.
//
import 'package:flutter/material.dart';
/// 混合動(dòng)畫回調(diào)類型
typedef AnimatedGroupBuilder = Widget Function(BuildContext context, Widget? child, List<Animation<dynamic>> animations);
class AnimatedGroup extends StatefulWidget {
/// 混合動(dòng)畫
AnimatedGroup({
Key? key,
required this.animations,
required this.builder,
this.controller,
this.duration = const Duration(milliseconds: 2000),
this.child,
}) : super(key: key);
/// 混合動(dòng)畫數(shù)組
List<AnimatedGroupItemModel> animations;
/// 混合動(dòng)畫回調(diào)
AnimatedGroupBuilder builder;
/// 控制器
AnimationController? controller;
/// AnimationController 控制的 duration 屬性
Duration? duration;
/// 不需要多次構(gòu)建的部分
Widget? child;
@override
AnimatedGroupState createState() => AnimatedGroupState();
}
/// 混合動(dòng)畫 State
class AnimatedGroupState extends State<AnimatedGroup> with TickerProviderStateMixin {
AnimationController? _controller;
/// 僅限于無法滿足功能時(shí)使用(透?jìng)鲗?duì)象, 方便二次開發(fā))
AnimationController get controller => _controller!;
List<Animation<dynamic>> _animations = [];
@override
void initState() {
_controller = widget.controller ?? AnimationController(duration: widget.duration, vsync: this);
_animations = widget.animations.map((e) => e.tween.animate(_buildAnim(e.begin, e.end))).toList();
super.initState();
}
@override
void dispose() {
_controller?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _controller!,
child: widget.child,
builder: (BuildContext context, Widget? child){
return widget.builder(context, child, _animations);
}
);
}
/// 開始執(zhí)行動(dòng)畫
///
/// isRemovedOnCompletion 是否單程動(dòng)畫
///
/// isReverse 是否逆轉(zhuǎn)動(dòng)畫
palyeAnimations({bool isRemovedOnCompletion = true, bool isReverse = false}) async {
try {
if (!isReverse) {
await _controller?.forward().orCancel;
if (!isRemovedOnCompletion) {
await _controller?.reverse().orCancel;
}
} else {
await _controller?.reverse().orCancel;
if (!isRemovedOnCompletion) {
await _controller?.forward().orCancel;
}
}
} on TickerCanceled {
// the animation got canceled, probably because we were disposed
};
}
/// 創(chuàng)建動(dòng)畫對(duì)象
CurvedAnimation _buildAnim(double begin, double end) {
return CurvedAnimation(
parent: _controller!,
curve: Interval(
begin,
end,
curve: Curves.ease,
),
);
}
}
/// 混合動(dòng)畫單個(gè)動(dòng)畫模型
class AnimatedGroupItemModel{
/// 混合動(dòng)畫單個(gè)動(dòng)畫模型
AnimatedGroupItemModel({
required this.tween,
required this.begin,
required this.end,
});
/// 動(dòng)畫 Tween
Tween tween;
/// 動(dòng)畫開始時(shí)間 (0 - 1.0)
double begin;
/// 動(dòng)畫結(jié)束時(shí)間 (0 - 1.0)
double end;
}
最后
代碼復(fù)制到項(xiàng)目中可直接運(yùn)行;
以上就是Flutter封裝組動(dòng)畫混合動(dòng)畫AnimatedGroup示例詳解的詳細(xì)內(nèi)容,更多關(guān)于Flutter封裝AnimatedGroup的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
OpenGL Shader實(shí)現(xiàn)簡(jiǎn)單轉(zhuǎn)場(chǎng)效果詳解
轉(zhuǎn)場(chǎng)效果常出現(xiàn)再視頻剪輯當(dāng)中,用于銜接兩段視頻片段切換的過渡效果。本文將介紹如何利用OpenGL Shader實(shí)現(xiàn)簡(jiǎn)單的轉(zhuǎn)場(chǎng)效果,需要的小伙伴可以參考一下2022-02-02
21天學(xué)習(xí)android開發(fā)教程之XML解析與生成
21天學(xué)習(xí)android開發(fā)教程之XML解析與生成,使用SAX來解析XML,在Android里面可以使用SAX和DOM,DOM需要把整個(gè)XML文件讀入內(nèi)存再解析,比較消耗內(nèi)存,而SAX基于事件驅(qū)動(dòng)的處理方式,可以在各節(jié)點(diǎn)觸發(fā)回調(diào)函數(shù),需要的朋友可以參考下2016-02-02
Android開發(fā)中的文件操作工具類FileUtil完整實(shí)例
這篇文章主要介紹了Android開發(fā)中的文件操作工具類FileUtil,結(jié)合完整實(shí)例形式分析了Android文件操作的常用技巧,包括文件的獲取、遍歷、搜索、復(fù)制、刪除、判斷等功能,需要的朋友可以參考下2017-11-11
android教程之使用asynctask在后臺(tái)運(yùn)行耗時(shí)任務(wù)
AsyncTask用在需要在ui線程中調(diào)用、在背景線程中執(zhí)行耗時(shí)任務(wù)、并且在ui線程中返回結(jié)果的場(chǎng)合。下面就是一個(gè)在背景中運(yùn)行的AsyncTask的實(shí)現(xiàn)DownloadDBTask2014-02-02
Android測(cè)量每秒幀數(shù)Frames Per Second (FPS)的方法
這篇文章主要介紹了Android測(cè)量每秒幀數(shù)Frames Per Second (FPS)的方法,涉及Android針對(duì)多媒體文件屬性操作的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10
Android實(shí)現(xiàn)底部切換標(biāo)簽
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)底部切換標(biāo)簽,嵌套Fragment,方便自定義布局,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-07-07
Android中AsyncTask異步任務(wù)使用詳細(xì)實(shí)例(一)
AsyncTask是Android提供的輕量級(jí)的異步類,可以直接繼承AsyncTask,在類中實(shí)現(xiàn)異步操作,并提供接口反饋當(dāng)前異步執(zhí)行的程度(可以通過接口實(shí)現(xiàn)UI進(jìn)度更新),最后反饋執(zhí)行的結(jié)果給UI主線程,通過本文給大家介紹Android中AsyncTask異步任務(wù)使用詳細(xì)實(shí)例(一),需要的朋友參考下2016-02-02

