老孟導讀:此文講解3個酷炫的3D動畫效果。git
下面是要實現的效果:微信
Flutter 中3D效果是經過 Transform 組件實現的,沒有變換效果的實現:app
class TransformDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('3D 變換Demo'),
),
body: Container(
alignment: Alignment.center,
color: Colors.white,
child: Text('3D 變換Demo'),
),
);
}
}複製代碼
經過 GestureDetector 組件添加滑動事件監聽:less
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('3D 變換Demo'),
),
body: GestureDetector(
onPanUpdate: (details) {
print('$details');
},
child: Container(
alignment: Alignment.center,
color: Colors.white,
child: Text('3D 變換Demo'),
),
),
);
}複製代碼
添加 Transform 對組件進入旋轉:ide
@override
Widget build(BuildContext context) {
return Transform(
transform: Matrix4.identity()
..setEntry(3, 2, 0.001)
..rotateX(pi/6)
..rotateY(pi/6),
alignment: Alignment.center,
child: Scaffold(
appBar: AppBar(
title: Text('3D 變換Demo'),
),
body: GestureDetector(
onPanUpdate: (details) {
},
child: Container(
alignment: Alignment.center,
color: Colors.white,
child: Text('3D 變換Demo'),
),
),
));
}複製代碼
將滑動的偏移和旋轉進行關聯:動畫
class TransformDemo extends StatefulWidget {
@override
_TransformDemoState createState() => _TransformDemoState();
}
class _TransformDemoState extends State<TransformDemo> {
double _rotateX = .0;
double _rotateY = .0;
@override
Widget build(BuildContext context) {
return Transform(
transform: Matrix4.identity()
..rotateX(_rotateX)
..rotateY(_rotateY),
alignment: Alignment.center,
child: Scaffold(
appBar: AppBar(
title: Text('3D 變換Demo'),
),
body: GestureDetector(
onPanUpdate: (details) {
setState(() {
_rotateX += details.delta.dy * .01;
_rotateY += details.delta.dx * -.01;
});
},
child: Container(
alignment: Alignment.center,
color: Colors.white,
child: Text('3D 變換Demo'),
),
),
));
}
}複製代碼
基本已經實現了3D效果,但效果比較生硬,尤爲垂直方向旋轉的時候遠點和近點在屏幕上的寬度是同樣,ui
添加近大遠小的效果:this
Transform(
transform: Matrix4.identity()
..setEntry(3, 2, 0.001)
..rotateX(_rotateX)
..rotateY(_rotateY),
...複製代碼
上面的效果相似於翻書的效果。spa
實現的原理:3d
將圖片左右切割爲兩部分,兩張圖片共分割爲4個新的組件,以下圖,分別爲一、二、三、4
代碼實現:
_child1 = ClipRect(
child: Align(
alignment: Alignment.centerLeft,
widthFactor: 0.5,
child: child1,
),
);
_child2 = ClipRect(
child: Align(
alignment: Alignment.centerRight,
widthFactor: 0.5,
child: child1,
),
);
_child3 = ClipRect(
child: Align(
alignment: Alignment.centerLeft,
widthFactor: 0.5,
child: child2,
),
);
_child4 = ClipRect(
child: Align(
alignment: Alignment.centerRight,
widthFactor: 0.5,
child: child2,
),
);複製代碼
將第一張圖片放在第二種圖片的上面,先旋轉 組件2 從 0度到 90度,而後再旋轉 組件3 從 -90度到0度,代碼實現:
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Stack(
children: [
_child1,
Transform(
alignment: Alignment.centerRight,
transform: Matrix4.identity()
..setEntry(3, 2, 0.001)
..rotateY(_animation1.value),
child: _child3,
),
],
),
Container(
width: 3,
color: Colors.white,
),
Stack(
children: [
_child4,
Transform(
alignment: Alignment.centerLeft,
transform: Matrix4.identity()
..setEntry(3, 2, 0.001)
..rotateY(_animation.value),
child: _child2,
)
],
)
],
)複製代碼
動畫控制器設置:
@override
void initState() {
init();
_controller =
AnimationController(vsync: this, duration: Duration(seconds: 5))
..addListener(() {
setState(() {});
});
_animation = Tween(begin: .0, end: pi / 2)
.animate(CurvedAnimation(parent: _controller, curve: Interval(.0, .5)));
_animation1 = Tween(begin: -pi / 2, end: 0.0).animate(
CurvedAnimation(parent: _controller, curve: Interval(.5, 1.0)));
_controller.forward();
super.initState();
}複製代碼
其中 child1, child2爲兩種圖片,代碼以下:
_FlipUpDemoState(
Container(
width: 300,
height: 400,
child: Image.asset(
'assets/images/b.jpg',
fit: BoxFit.cover,
),
),
Container(
width: 300,
height: 400,
child: Image.asset(
'assets/images/c.jpeg',
fit: BoxFit.cover,
),
))複製代碼
最後生成的效果就是開始的翻書效果。
上面是左右翻頁效果,同理換成上下翻頁效果:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Stack(
children: [
_upperChild1,
Transform(
alignment: Alignment.bottomCenter,
transform: Matrix4.identity()
..setEntry(3, 2, 0.003)
..rotateX(_animation1.value),
child: _upperChild2,
),
],
),
SizedBox(
height: 2,
),
Stack(
children: [
_lowerChild2,
Transform(
alignment: Alignment.topCenter,
transform: Matrix4.identity()
..setEntry(3, 2, 0.003)
..rotateX(_animation.value),
child: _lowerChild1,
)
],
)
],
),
);
}複製代碼
老孟Flutter博客地址(330個控件用法):laomengit.com
歡迎加入Flutter交流羣(微信:laomengit)、關注公衆號【老孟Flutter】: