您作為用戶的經(jīng)歷多次點擊沒有動畫的按鈕谎僻,因為您不知道它是否確實發(fā)送了您請求的操作?如果按鈕有一個輕微的動畫告訴你它實際被點擊了艘绍,你就不需要做了多次同樣的事情。
什么是動畫挎挖?我們?yōu)槭裁匆褂盟鼈儯?/h4>
在為您的應(yīng)用程序創(chuàng)建良好的用戶體驗時,添加制作精良且流暢的動畫至關(guān)重要航夺。它們作為用戶行為的視覺反饋蕉朵,也可以提供互動和保證的意義阳掐。
動畫按鈕就是本文的內(nèi)容堪伍,特別是我們將構(gòu)建一個小型彈跳動畫,當用戶單擊按鈕時會觸發(fā)該動畫觅闽。
首先帝雇,按鈕布局
按鈕布局基于一個簡單的容器,其中心有一個文本小部件蛉拙。
Widget get _animatedButtonUI => Container(
height: 100,
width: 250,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(100),
boxShadow: [ shadow ],
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Color(0xFFA7BFE8),
Color(0xFF6190E8),
],
),
),
child: Center(
child: Text(
'tap!',
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
);
我們來看看動畫
我們需要使用setState()和dispose()函數(shù)孕锄,因此我們將擴展StatefulWidget吮廉。
class AnimatedButton extends StatefulWidget {
@override
_AnimatedButtonState createState() => _AnimatedButtonState();
}
class _AnimatedButtonState extends State<AnimatedButton> {
@override
Widget build(BuildContext context) {
return Container();
}
Widget get _animatedButtonUI => ...
}
我們都準備開始制作動畫了宦芦。
讓我們實現(xiàn)SingleTickerProviderStateMixin并定義我們創(chuàng)建動畫所需的兩個屬性轴脐。
class _AnimatedButtonState extends State<AnimatedButton> with SingleTickerProviderStateMixin {
double _scale;
AnimationController _controller;
@override
Widget build(BuildContext context) {
return Container();
}
...
}
現(xiàn)在是時候通過重寫initState()來初始化我的_controller并通過覆蓋dispose()函數(shù)來處理它
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: Duration(milliseconds: 200),
lowerBound: 0.0,
upperBound: 0.1,
)
..addListener(() { setState(() {});});
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
接下來,我們定義了兩個函數(shù)大咱,一個用于按下按鈕,另一個用于釋放按鈕時溯捆,前者將告訴我們的控制器繼續(xù)前進厦瓢,而后者則反過來
void _onTapDown(TapDownDetails details) {
_controller.forward();
}
void _onTapUp(TapUpDetails details) {
_controller.reverse();
}
最后,在我們的構(gòu)建函數(shù)中煮仇,我們設(shè)置了scale變量,讓GestureDetector處理tapDown和tapUp屬性售碳,然后使用Transform小部件進行縮放
@override
Widget build(BuildContext context) {
_scale = 1 - _controller.value;
return GestureDetector(
onTapDown: _onTapDown,
onTapUp: _onTapUp,
child: Transform.scale(
scale: _scale,
child: _animatedButtonUI,
),
);
}
這是最終的結(jié)果
結(jié)論
這是一篇關(guān)于如何創(chuàng)建簡單而有效的動畫的快速文章绞呈,我希望這將有助于您改進應(yīng)用程序用戶體驗间景。
全部代碼
import 'package:flutter/material.dart';
class AnimatedButton extends StatefulWidget {
@override
_AnimatedButtonState createState() => _AnimatedButtonState();
}
class _AnimatedButtonState extends State<AnimatedButton>
with SingleTickerProviderStateMixin {
double _scale;
AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: Duration(milliseconds: 200),
lowerBound: 0.0,
upperBound: 0.1,
)..addListener(() {
setState(() {});
});
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
void _onTapDown(TapDownDetails details) {
_controller.forward();
}
void _onTapUp(TapUpDetails details) {
_controller.reverse();
}
@override
Widget build(BuildContext context) {
_scale = 1 - _controller.value;
return GestureDetector(
onTapDown: _onTapDown,
onTapUp: _onTapUp,
child: Transform.scale(
scale: _scale,
child: _animatedButtonUI,
),
);
}
Widget get _animatedButtonUI => Container(
height: 100,
width: 250,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(100),
boxShadow: [
BoxShadow(
color: Color(0x80000000),
blurRadius: 30.0,
offset: Offset(0.0, 30.0),
),
],
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Color(0xFFA7BFE8),
Color(0xFF6190E8),
],
),
),
child: Center(
child: Text(
'tap!',
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
);
}