Flutter封装组动画混合动画AnimatedGroup示例详解
作者:SoaringHeart 发布时间:2022-12-29 17:17:05
标签:Flutter,AnimatedGroup,动画封装
一、来源
项目中遇到混合动画的情况,每次实现都需要生命一堆属性,让代码变得杂乱,难以维护。
参考 iOS 组动画 CAAimationGroup, 随花半天时间封装一个混合动画组件 AnimatedGroup。
此组件基于极简、高扩展、高适用的封装原则,基本满足当前项目开发。
二、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 混合动画", 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';
/// 混合动画回调类型
typedef AnimatedGroupBuilder = Widget Function(BuildContext context, Widget? child, List<Animation<dynamic>> animations);
class AnimatedGroup extends StatefulWidget {
/// 混合动画
AnimatedGroup({
Key? key,
required this.animations,
required this.builder,
this.controller,
this.duration = const Duration(milliseconds: 2000),
this.child,
}) : super(key: key);
/// 混合动画数组
List<AnimatedGroupItemModel> animations;
/// 混合动画回调
AnimatedGroupBuilder builder;
/// 控制器
AnimationController? controller;
/// AnimationController 控制的 duration 属性
Duration? duration;
/// 不需要多次构建的部分
Widget? child;
@override
AnimatedGroupState createState() => AnimatedGroupState();
}
/// 混合动画 State
class AnimatedGroupState extends State<AnimatedGroup> with TickerProviderStateMixin {
AnimationController? _controller;
/// 仅限于无法满足功能时使用(透传对象, 方便二次开发)
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);
}
);
}
/// 开始执行动画
///
/// isRemovedOnCompletion 是否单程动画
///
/// isReverse 是否逆转动画
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
};
}
/// 创建动画对象
CurvedAnimation _buildAnim(double begin, double end) {
return CurvedAnimation(
parent: _controller!,
curve: Interval(
begin,
end,
curve: Curves.ease,
),
);
}
}
/// 混合动画单个动画模型
class AnimatedGroupItemModel{
/// 混合动画单个动画模型
AnimatedGroupItemModel({
required this.tween,
required this.begin,
required this.end,
});
/// 动画 Tween
Tween tween;
/// 动画开始时间 (0 - 1.0)
double begin;
/// 动画结束时间 (0 - 1.0)
double end;
}
最后
代码复制到项目中可直接运行;
github
来源:https://juejin.cn/post/7190184512532414522


猜你喜欢
- 本文实例为大家分享了C语言运用函数指针数组制作计算器的具体代码,供大家参考,具体内容如下先来回顾一下概念:指针数组 —— 存放指针的数组函数
- 最近因考虑接口安全问题,有实现给WEB API实现统一的参数鉴权功能,以防止请求参数被篡改或重复执行,参数鉴权方法基本与常见的鉴权思路相同,
- 目录查查询指定列查询所有列条件查询子查询根据业务逻辑添加条件连接查询增新增一条批量新增删改主要演示DynamicSql风格代码如何使用,基本
- 这篇文章主要介绍一下如何实现View的3D旋转效果,实现的主要原理就是围绕Y轴旋转,同时在Z轴方面上有一个深入的缩放。演示的demo主要有以
- 在android平板上用webview打开一个网页,调用里面的javascript方法,同时相互传参。网上例子很少啊,基本都不能获取返回值,
- 1、Hello, KotlinBugly 技术干货系列内容主要涉及移动开发方向,是由 Bugly 邀请腾讯内部各位技术大咖,通过日常工作经验
- .net core提供了Json处理模块,在命名空间System.Text.Json中,下面通过顶级语句,对C#的Json功能进行讲解。序列
- Exception e中e的getMessage()和toString()方法的区别:示例代码1:public class TestInfo
- 效果展示人脸支付效果视频密码框输入支付效果视频因为密码支付时会调起系统安全键盘,开启自动保护功能,防止泄露,会导致输入密码时录屏黑屏,故使用
- 一,内部类访问成员1,内部类可以直接访问外部类的成员,包括私有。2,外部类要访问内部类,必须建立内部类对象。class Outer{int
- 本文实例总结了C# XML序列化方法及常用特性。分享给大家供大家参考,具体如下:C#对象XML序列化(一):序列化方法和常用特性.Net F
- c语言颜色代码初学c的小伙伴可能已经对那个黑底白字的框有些厌倦了,不妨加点颜色,增加加可读性。/*颜色函数SetConsoleTextAtt
- 1、LongAdder由来LongAdder类是JDK1.8新增的一个原子性操作类。AtomicLong通过CAS算法提供了非阻塞的原子性操
- Android Intent调用 Uri的方法总结//调用浏览器Uri uri = Uri.parse(""); Int
- 崩溃来源使用过AIDL进行跨进程通信的同学,肯定遇到过DeadObjectException这个崩溃,那么这个崩溃是怎么来的,我们又该如何解
- 导入依赖菜单大部分情况下不会出现变化,我们可以将其放入Redis 加快加载速度<dependency><groupId&g
- 自定义控件是根据自己的需要自己来编写控件。安卓自带的控件有时候无法满足你的需求,这种时候,我们只能去自己去实现适合项目的控件。同时,安卓也允
- 1、概述Spring Retry 是Spring框架中的一个组件,它提供了自动重新调用失败操作的能力。这在错误可能是暂时发生的(如瞬时网络故
- 注:由于工作需要, 也是第一次接触到打印机的相关内容, 凑巧, 通过找了很多资料和帮助后, 也顺利的解决了打印标签的问题(标签的表面信息[二
- 本文实例介绍的是Android的Tab控件,Tab控件可以达到分页的效果,让一个屏幕的内容尽量丰富,当然也会增加开发的复杂程度,在有必要的时