Flutter 学习(三) dart基础canvas
Flutter学习(五) 基础控件 以及ios的Cupertino风格ide
前几篇文章讲了一些基础widget 的使用方式,这篇文章会介绍flutter 动画部分的简单使用.布局
AnimationController会产生数值0--1区间内的数值变换,也能够控制动画 reverse(),forward(),animateTo()等
构造参数中vsync
绑定管理动画执行的定时器,widget不显示时暂停动画,显示时回复动画,Duration
设置动画时间post
AnimationController _animController =
AnimationController(vsync: this, duration: Duration(seconds: 2))
..reverse();
复制代码
若是你想产生 0--1 以外的数值变换 可使用Tween
来实现,当前Tween 不单单只能是数值类型的 能够是颜色 曲线等类型ColorTween CurveTween
具体能够查看官网API文档说明. 使用时须要调用animate()
方法去传入控制器,这里传入的参数是 Animation因此 除了控制器也能够去传入一个 Animation的动画,另外也可使用 addListener() addStatusListener()
去监听动画执行过程 以及状态,经过 value()
去获取当前的数值 做用到 widget上学习
//产生数值
AnimationController _animController =
AnimationController(vsync: this, duration: Duration(seconds: 2));
_animtion = Tween<double>(begin:100.0, end:
final Animation curve =new CurvedAnimation(parent: _animController, curve: Curves.easeOut);
200.0).animate(curve)
..addListener(() {
setState(() {
_currentValue = _animtion.value;
});
})
..addStatusListener((status) {
if (status == AnimationStatus.completed) {
_animController.reverse();
} else if (status == AnimationStatus.forward) {
_animController.forward();
}
});
//使用
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(onPressed: () {
_animController.forward();
}),
body: Center(
child: Container(
width: _currentValue,
height: _currentValue,
color: Colors.blue,
child: Text('$_currentValue'),
),
),
);
}
复制代码
使用时继承这个Widget,在使用 Tween
动画时 在数值产生时须要去调用setState((){})
去 重绘布局, 若是使用AnimatedWidget
能够省略这部 它内部会直接对状态更新进行管理. controller 和 animation 从外部传入,建立方式跟Twee
同样 ,在构造中传入 anim 对象动画
//控制器对象建立
@override
void initState() {
super.initState();
_animController =
AnimationController(vsync: this, duration: Duration(seconds: 2));
_animtion = Tween<double>(begin: 100.0, end: 200.0).animate(_animController)
..addListener(() {
setState(() {
_currentValue = _animtion.value;
});
})
..addStatusListener((status) {
if (status == AnimationStatus.completed) {
_animController.reverse();
} else if (status == AnimationStatus.forward) {
_animController.forward();
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(onPressed: () {
_animController.forward();
}),
body: MyLogo(
anim: _animtion,
),
);
}
//动画widget
class MyLogo extends AnimatedWidget {
MyLogo({Key key, @required Animation anim}) : super(listenable: anim);
final Tween<double> _rotateAnim = Tween<double>(begin: 0.0, end: 100.0);
final Tween<double> _scaleAnim = Tween<double>(begin: 1.0, end: 10.0);
@override
Widget build(BuildContext context) {
Animation anim = listenable;
return Center(
child: Transform.rotate(
angle: _rotateAnim.evaluate(anim),
child: Transform.scale(
scale: _scaleAnim.evaluate(anim),
child: Container(
/* width: anim.value,
height: anim.value,*/
child: FlutterLogo(),
),
),
),
);
}
}
复制代码
分离对象与Widget,使用AnimatedBuilder将动画描述为另外一个widget的build方法的一部分,controller animation 建立与前面一致ui
@override
Widget build(BuildContext context) {
double _screenWidth = MediaQuery.of(context).size.width;
return Scaffold(
floatingActionButton: FloatingActionButton(onPressed: () {
_animController.forward();
}),
body: Center(
child: AnimatedBuilder(
animation: _animtion,
builder: (context, child) {
return Transform(
child: Container(width: 200, height: 200, child: FlutterLogo()),
transform: Matrix4.translationValues(
_screenWidth * _animtion.value, 0, 0),
);
}),
),
);
}
复制代码
能够对一个widget 同时作动画 透明度和 宽高改变
class AnimatedLogo extends AnimatedWidget {
// The Tweens are static because they don't change. static final _opacityTween = new Tween<double>(begin: 0.1, end: 1.0); static final _sizeTween = new Tween<double>(begin: 0.0, end: 300.0); AnimatedLogo({Key key, Animation<double> animation}) : super(key: key, listenable: animation); Widget build(BuildContext context) { final Animation<double> animation = listenable; return new Center( child: new Opacity( opacity: _opacityTween.evaluate(animation), child: new Container( margin: new EdgeInsets.symmetric(vertical: 10.0), height: _sizeTween.evaluate(animation), width: _sizeTween.evaluate(animation), child: new FlutterLogo(), ), ), ); } } 复制代码
在原生 java 中 自定义控件 须要用到 画笔paint
画布canvas
在flutter中也是用这些来绘制页面, 使用的时候须要用到CustomPaint
包裹本身定义的Painter
,paint canvas的使用与java 相似就不在赘述
//使用方式
child: CustomPaint(
size: Size(30, 30),
painter: HeartPainter(),
),
//绘制页面
class HeartPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
// TODO: implement paint
Paint paint = Paint();
paint
..color = Color(0xffff0000)
..style = PaintingStyle.fill
..strokeWidth = 5;
double width = size.width;
double height = size.height;
Path path = Path();
path.moveTo(0.5 * width, height * 0.35);
path.cubicTo(0.2 * width, height * 0.1, -0.25 * width, height * 0.6,
0.5 * width, height);
path.moveTo(0.5 * width, height * 0.35);
path.cubicTo(0.8 * width, height * 0.1, 1.25 * width, height * 0.6,
0.5 * width, height);
canvas.drawPath(path, paint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
复制代码
Transform 能够对子widget 作一些矩阵变化,达到必定的效果
相似原生中的页面共享动画,在页面A用Hero 包裹想要进行动画的 widget 并设置tag ,在跳转以后的B页面 一样适用Hero 包裹widget 设置相同的 tag
Hero(
tag: "avatar", //惟一标记,先后两个路由页Hero的tag必须相同
child: ClipOval(
child: Image.asset("images/avatar.png",
width: 50.0,
),
),
复制代码
Navigator.push(context, CupertinoPageRoute(
builder: (context)=>PageB(),
));
Navigator.push(
context,
PageRouteBuilder(
transitionDuration: Duration(milliseconds: 500), //动画时间为500毫秒
pageBuilder: (BuildContext context, Animation animation,
Animation secondaryAnimation) {
return new FadeTransition(
//使用渐隐渐入过渡,
opacity: animation,
child: PageB(), //路由B
);
},
),
);
复制代码