flutter如何做一个点击后有动画的组件
[TOC]
AnimationController动画控制器
说明
- 只可以为double值,因此我们才需要Animation来做动画对象,AnimationController做控制器
AnimationController({
double? value,
this.duration,
this.reverseDuration,
this.debugLabel,
this.lowerBound = 0.0,
this.upperBound = 1.0,
this.animationBehavior = AnimationBehavior.normal,
required TickerProvider vsync,
})
示例
class _MyHomePageState extends State<MyHomePage> with SingleTickerProvider特性StateMixin //具备TickerProvider特性
//定义动画初始值
AnimationController _controller;
double _size = 100;
//动画监听
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: Duration(milliseconds: 500),
//初始值
lowerBound: 100,
//value最大值
upperBound: 200)
..addStatusListener((AnimationStatus status) {
if(status == AnimationStatus.completed){
_controller.reverse();
}else if(status == AnimationStatus.dismissed){
_controller.forward();
}
})
..addListener(() {
setState(() {
_size = _controller.value;
});
});
}
//body
Center(
child: GestureDetector(
onTap: (){_controller.forward();},
child: Container(
height: _size,
width: _size,
color: Colors.blue,
alignment: Alignment.center,
child: Text("点我,开始动画"),
),
),
)
//释放资源
@override
void dispose() {
super.dispose();
_controller.dispose();
}
vsync
- vsync:TickerProvider(抽象类),用于接收动画变化过程中的通知,类似于接口回调
- 用户在使用时可以选择TickerProviderStateMixin或SingleTickerProviderStateMixin
- 混入mixins时,使用关键字with,
mixin
是一种在多个类层次结构中重用类代码的方法 - 单个 AnimationController 的时候使用 SingleTickerProviderStateMixin
- 多个 AnimationController 使用 TickerProviderStateMixin
Animation动画
说明
- 可以为任意的值
- 可以是非线性执行
- 是一个抽象类
Tween
- 继承了Animatable
- Tween是一个无状态(stateless)对象,需要begin和end值。Tween的唯一职责就是定义从输入范围到输出范围的映射。输入范围通常为0.0到1.0,但这不是必须的。
- Tween对象不存储任何状态。相反,它提供了evaluate(Animation
animation)方法获取动画当前值。 Animation对象的当前值可以通过value()方法取到。evaluate函数还执行一些其它处理,例如分别确保在动画值为0.0和1.0时返回开始和结束状态,这个方法一般不需要使用,除非想要获取特定时间的动画值 - 通常需要使用它的animation()的方法创建一个
Animation
对象。
示例
_animationController = new AnimationController(vsync: this,duration: new Duration(milliseconds: 3000));
_animation = new CurvedAnimation(parent: _animationController, curve: Curves.easeIn)
..addListener((){
setState(() {
});
});
_sizeTween = new Tween(begin: 0.0,end: 300.0);
_colorTween = new ColorTween(begin: Colors.transparent,end: Colors.amberAccent);
_animationController.forward();
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return new Scaffold(
appBar: new AppBar(
title: new Text('animation'),
),
body: new Center(
child: new Container(
color: _colorTween.evaluate(_animation),
width: _sizeTween.evaluate(_animation),
height: _sizeTween.evaluate(_animation),
),
),
);
源码
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class UserMsg extends StatefulWidget {
UserMsg({super.key, required this.text});
String text;
@override
State<UserMsg> createState() => _UserMsgState();
}
class _UserMsgState extends State<UserMsg> with SingleTickerProviderStateMixin {
late AnimationController _animationController;
late Animation<double> _scaleAnimation;
final _initialScale = 1.0;
final _tappedScale = 1.1;
@override
void initState() {
super.initState();
_animationController = AnimationController(
duration: const Duration(milliseconds: 300),
vsync: this,
);
_scaleAnimation = Tween<double>(
begin: _initialScale,
end: _tappedScale,
).animate(_animationController);
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
void _onEnter(PointerEnterEvent event) {
if (_animationController.status != AnimationStatus.forward) {
//动画开始执行
_animationController.forward();
}
}
void _onExit(PointerExitEvent event) {
//反向执行
_animationController.reverse();
}
@override
Widget build(BuildContext context) {
return MouseRegion(
onEnter: _onEnter,
onExit: _onExit,
child: GestureDetector(
child: ScaleTransition(
scale: _scaleAnimation,
child: Container(
width: MediaQuery.of(context).size.width * 0.3,
height: MediaQuery.of(context).size.width * 0.04,
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(20)),
border: Border.all(
color: Colors.black, // 边框颜色
width: 4.0, // 边框宽度
),
),
child: Center(
child: Text(
widget.text,
style: TextStyle(
fontSize: MediaQuery.of(context).size.width * 0.02,
),
),
),
),
),
));
}
}
Comments are closed