dependencies:
toggle_rotate: $lastVersion
複製程式碼
一、描述
目標: 讓一個元件點選時執行旋轉,再點選旋轉回去。
最簡使用 | 時長、曲線、方向 | 可含一切元件 | 旋轉角度 |
---|---|---|---|
1.所有屬性:
名稱 | 型別 | 功能 | 備註 | 預設 |
---|---|---|---|---|
rad | double | 旋轉角度 | 弧度制 | pi / 2 |
durationMs | int | 動畫時長 | 毫秒 | 200 |
curve | Curve | 動畫曲線 | - | Curves.fastOutSlowIn |
clockwise | bool | 是否順時針旋轉 | - | true |
onTap | Function | 點選事件 | @required | null |
child | Widget | 子元件 | @required | null |
2.最簡使用:
ToggleRotate(
child: Icon(Icons.arrow_upward,size: 60,color: Colors.orangeAccent),
onTap: () {}, //點選事件
),
複製程式碼
3.指定時長和曲線和方向
ToggleRotate(
curve: Curves.decelerate,
durationMs: 400,//動畫時長
clockwise: false, //是否是順時針
child: Icon(Icons.arrow_upward,size: 60,color: Colors.orangeAccent),
onTap: () {},
),
複製程式碼
4.可使一切元件進行旋轉切換
ToggleRotate(
curve: Curves.decelerate,
durationMs: 400,
child: Image(width:60,height: 60,image: AssetImage("assets/images/icon_28.jpg")),
onTap: () {},
)
複製程式碼
5.可使旋轉的角度
ToggleRotate(
rad: pi / 4,
curve: Curves.linear,
child: Image(width:60,height: 60,image: AssetImage("assets/images/icon_28.jpg")),
onTap: () {},
)
複製程式碼
二、實現原理
點選時進行一些動畫效果比較好看,順便抽離成一個元件分享一下
這個小元件是一個動畫的經典案例,所以分析一下具體實現還是很有意義的
1.自定義元件
開始分析一下是否有狀態。很明顯,我們需要在點選時讓元件旋轉
元件有是否旋轉是一個狀態量,旋轉過程中的角度也是狀態量
可以說想要實現動畫,基本上是基於StatefulWidget的,先寫出一個基本的元件
由於需要動畫,要with SingleTickerProviderStateMixin
library toggle_rotate;
import 'dart:math';
import 'package:flutter/material.dart';
class ToggleRotate extends StatefulWidget {
final Widget child;
final Function onTap;
final double rad;
final int durationMs;
final bool clockwise;
final Curve curve;
ToggleRotate(
{this.child,
@required this.onTap,
this.rad = pi / 2,
this.clockwise = true,
this.durationMs = 200,
this.curve = Curves.fastOutSlowIn});
@override
_ToggleRotateState createState() => _ToggleRotateState();
}
class _ToggleRotateState extends State<ToggleRotate> with SingleTickerProviderStateMixin {
@override
void initState() {
super.initState();
}
@override
void dispose()
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container();
}
}
複製程式碼
2.動畫器的建立和銷燬
狀態量有旋轉的弧
_rad
、是否已旋轉_rotated
。
動畫器AnimationController負責讓數字在0.0~1.0之間均勻變化
通過CurvedAnimation來讓數字變化率為曲線
核心就是確定每次更新狀態時弧度的大小。 通過addListener可以在動畫器每次重新整理時進行監聽
通過addStatusListener對動畫的狀態進行監聽,如果完成_rotated置反
class _ToggleRotateState extends State<ToggleRotate>
with SingleTickerProviderStateMixin {
double _rad = 0;
bool _rotated = false;
AnimationController _controller;
Animation _rotate;
@override
void initState() {
_controller = AnimationController(
duration: Duration(milliseconds: widget.durationMs), vsync: this)
..addListener(() => setState(() =>
_rad = (_rotated ? (1 - _rotate.value) : _rotate.value) * widget.rad))
..addStatusListener((status) {
if (status == AnimationStatus.completed) {
_rotated = !_rotated;
}
});
_rotate = CurvedAnimation(parent: _controller, curve: widget.curve);
super.initState();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
複製程式碼
3.通過Transform實現變換
在點選時先重設控制器,然後再執行。否則第二次是不會動的
在這裡只用onTap回撥點選事件,暴露給外界處理。
clockwise決定是否是順時針旋轉,這樣該元件就完成了。
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
_controller.reset();
_controller.forward();
widget.onTap();
},
child: Transform(
transform: Matrix4.rotationZ(widget.clockwise ? _rad : -_rad),
alignment: Alignment.center,
child: widget.child,
),
);
}
複製程式碼
麻雀雖小五臟俱全,這個小元件雖然就60行左右的程式碼,但包含很多知識點。
如果你想要一個元件在點選時不那麼古板,歡迎使用
尾聲
另外本人有一個Flutter微信交流群,歡迎小夥伴加入,共同探討Flutter的問題,期待與你的交流與切磋。
@張風捷特烈 2019.02.23 未允禁轉
我的公眾號:程式設計之王
聯絡我--郵箱:1981462002@qq.com --微信:zdl1994328
~ END ~