Android?Flutter實現(xiàn)彈簧動畫交互的示例詳解
物理模擬可以讓應用程序的交互感覺逼真和互動,例如,你可能希望為一個 Widget 設(shè)置動畫,使其看起來像是附著在彈簧上或是重力下落。本文章實現(xiàn)了演示了如何使用彈簧模擬將小部件從拖動的點移回中心。
實現(xiàn)步驟如下
- 設(shè)置動畫控制器
- 使用手勢移動小部件
- 為小部件制作動畫
- 計算速度以模擬彈簧運動
1.創(chuàng)建一個動畫控制器
首頁創(chuàng)建一個測試使用的Demo頁面
void main() {
runApp(const MaterialApp(home: PhysicsCardDragDemo()));
}
class PhysicsCardDragDemo extends StatelessWidget {
const PhysicsCardDragDemo({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: const DraggableCard(
child: FlutterLogo(
size: 128,
),
),
);
}
}DraggableCard 是自定義的一個 StatefulWidget,代碼如下:
class _DraggableCardState extends State<DraggableCard> {
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return Align(
child: Card(
child: widget.child,
),
);
}
}然后在 _DraggableCardState 中創(chuàng)建一個動畫控制器,并在頁面銷毀的時候釋放動畫控制器,代碼如下:
class _DraggableCardState extends State<DraggableCard>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(vsync: this, duration: const Duration(seconds: 1));
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Align(
child: Card(
child: widget.child,
),
);
}
}SingleTickerProviderStateMixin是用來在StatefulWidget中管理單個AnimationController的Mixin;它提供了一個TickerProvider,用于將AnimationController與TickerProviderStateMixin一起使用。
TickerProviderStateMixin提供了一個Ticker,它可以在每個frame中調(diào)用AnimationController的方法,這使得AnimationController可以在每個frame中更新動畫。
2.使用手勢移動Widget
在 _DraggableCardState 中,結(jié)合使用 Alignment 與 GestureDetector,代碼如下:
class _DraggableCardState extends State<DraggableCard>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
Alignment _dragAlignment = const Alignment(0, 0);
@override
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size;
return GestureDetector(
onPanDown: (details) {},
onPanUpdate: (details) {
_dragAlignment += Alignment(
details.delta.dx / (size.width / 2),
details.delta.dy / (size.height / 2),
);
setState(() {
});
},
onPanEnd: (details) {},
child: Align(
alignment: _dragAlignment,
child: Card(
child: widget.child,
),
),
);
}GestureDetector用來檢測手勢,例如輕觸、滑動、拖動等,可以用來實現(xiàn)各種交互效果。
Alignment用于控制子widget在父widget中的位置??梢酝ㄟ^Alignment的構(gòu)造函數(shù)來指定子widget相對于父widget的位置,如Alignment.topLeft表示子widget位于父widget的左上角。也可以通過FractionalOffset來指定子widget相對于父widget的位置,如FractionalOffset(0.5, 0.5)表示子widget位于父widget的中心。Alignment還可以與Stack一起使用,實現(xiàn)多個子widget的定位。

3.創(chuàng)建一個動畫Widget
我們需要實現(xiàn),當手指抬起時,被移動的 Widget 動畫的方式彈回去。
在這里需要一個 Animation ,再定義一個 runAnimation 方法,同時為 第一步創(chuàng)建的動畫控制器添加一個更新監(jiān)聽。
class _DraggableCardState extends State<DraggableCard>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<Alignment> _animation;
@override
void initState() {
super.initState();
_controller =
AnimationController(vsync: this, duration: const Duration(seconds: 1));
_controller.addListener(() {
setState(() {
_dragAlignment = _animation.value;
});
});
}
void _runAnimation() {
_animation = _controller.drive(
AlignmentTween(
begin: _dragAlignment,
end: Alignment.center,
),
);
_controller.reset();
_controller.forward();
}
}然后在手指抬起的時候,執(zhí)行動畫,將被移動的 Widget (如這里的圖片)以動畫的方式移動回原位:
@override
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size;
return GestureDetector(
onPanDown: (details) {
_controller.stop();
},
onPanUpdate: (details) {
_dragAlignment += Alignment(
details.delta.dx / (size.width / 2),
details.delta.dy / (size.height / 2),
);
setState(() {
});
},
onPanEnd: (details) {
_runAnimation();
},
child: Align(
alignment: _dragAlignment,
child: Card(
child: widget.child,
),
),
);
}
4.計算速度以模擬彈簧運動
最后一步是做一些數(shù)學運算,計算小部件完成拖動后的速度。這是為了使小部件在被拍回之前能夠以這種速度逼真地繼續(xù)。(_runAnimation方法已經(jīng)通過設(shè)置動畫的開始和結(jié)束對齊來設(shè)置方向。)
導入包如下:
import 'package:flutter/physics.dart';
onPanEnd回調(diào)提供了一個DragEndDetails對象。此對象提供指針停止接觸屏幕時的速度。速度以像素每秒為單位,但Align小部件不使用像素。它使用介于[-1.0,-1.0]和[1.0,1.0]之間的坐標值,其中[0.0,0.0]表示中心。步驟2中計算的大小用于將像素轉(zhuǎn)換為該范圍內(nèi)的坐標值。
然后修改 runAnimation 執(zhí)行動畫函數(shù)如下:
void _runAnimation(Offset pixelsPerSecond, Size size) {
_animation = _controller.drive(
AlignmentTween(
begin: _dragAlignment,
end: Alignment.center,
),
);
final unitsPerSecondX = pixelsPerSecond.dx / size.width;
final unitsPerSecondY = pixelsPerSecond.dy / size.height;
final unitsPerSecond = Offset(unitsPerSecondX, unitsPerSecondY);
final unitVelocity = unitsPerSecond.distance;
//它可以用于模擬彈簧的阻尼、質(zhì)量和剛度等屬性,從而實現(xiàn)更加真實的動畫效果。
const spring = SpringDescription(
mass: 30,
stiffness: 1,
damping: 1,
);
//SpringSimulation用來模擬一個彈簧的運動,可以用于創(chuàng)建具有彈性的動畫效果。
final simulation = SpringSimulation(spring, 0, 1, -unitVelocity);
_controller.animateWith(simulation);
}然后在手指抬起的時候調(diào)用
onPanEnd: (details) {
_runAnimation(details.velocity.pixelsPerSecond, size);
},
以上就是Android Flutter實現(xiàn)彈簧動畫交互的示例詳解的詳細內(nèi)容,更多關(guān)于Android Flutter彈簧動畫交互的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android開發(fā)實現(xiàn)webview中img標簽加載本地圖片的方法
這篇文章主要介紹了Android開發(fā)實現(xiàn)webview中img標簽加載本地圖片的方法,結(jié)合實例形式分析了webview加載本地圖片的步驟與相關(guān)操作技巧,需要的朋友可以參考下2017-10-10
android使用ExpandableListView控件實現(xiàn)小說目錄效果的例子
這篇文章主要介紹了android使用ExpandableListView控件實現(xiàn)小說目錄效果的例子,還可以實現(xiàn)二級列表展示效果,需要的朋友可以參考下2014-07-07
Android使用AudioRecord實現(xiàn)暫停錄音功能實例代碼
本篇文章主要介紹了Android使用AudioRecord實現(xiàn)暫停錄音功能實例代碼,具有一定的參考價值,有興趣的可以了解一下2017-06-06
Android?獲取實時網(wǎng)速實現(xiàn)詳解
這篇文章主要為大家介紹了Android?獲取實時網(wǎng)速實現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-11-11

