Android?Flutter實(shí)現(xiàn)彈簧動(dòng)畫交互的示例詳解
物理模擬可以讓應(yīng)用程序的交互感覺(jué)逼真和互動(dòng),例如,你可能希望為一個(gè) Widget 設(shè)置動(dòng)畫,使其看起來(lái)像是附著在彈簧上或是重力下落。本文章實(shí)現(xiàn)了演示了如何使用彈簧模擬將小部件從拖動(dòng)的點(diǎn)移回中心。
實(shí)現(xiàn)步驟如下
- 設(shè)置動(dòng)畫控制器
- 使用手勢(shì)移動(dòng)小部件
- 為小部件制作動(dòng)畫
- 計(jì)算速度以模擬彈簧運(yùn)動(dòng)
1.創(chuàng)建一個(gè)動(dòng)畫控制器
首頁(yè)創(chuàng)建一個(gè)測(cè)試使用的Demo頁(yè)面
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 是自定義的一個(gè) 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)建一個(gè)動(dòng)畫控制器,并在頁(yè)面銷毀的時(shí)候釋放動(dò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是用來(lái)在StatefulWidget中管理單個(gè)AnimationController的Mixin;它提供了一個(gè)TickerProvider,用于將AnimationController與TickerProviderStateMixin一起使用。
TickerProviderStateMixin提供了一個(gè)Ticker,它可以在每個(gè)frame中調(diào)用AnimationController的方法,這使得AnimationController可以在每個(gè)frame中更新動(dòng)畫。
2.使用手勢(shì)移動(dòng)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用來(lái)檢測(cè)手勢(shì),例如輕觸、滑動(dòng)、拖動(dòng)等,可以用來(lái)實(shí)現(xiàn)各種交互效果。
Alignment用于控制子widget在父widget中的位置??梢酝ㄟ^(guò)Alignment的構(gòu)造函數(shù)來(lái)指定子widget相對(duì)于父widget的位置,如Alignment.topLeft表示子widget位于父widget的左上角。也可以通過(guò)FractionalOffset來(lái)指定子widget相對(duì)于父widget的位置,如FractionalOffset(0.5, 0.5)表示子widget位于父widget的中心。Alignment還可以與Stack一起使用,實(shí)現(xiàn)多個(gè)子widget的定位。
3.創(chuàng)建一個(gè)動(dòng)畫Widget
我們需要實(shí)現(xiàn),當(dāng)手指抬起時(shí),被移動(dòng)的 Widget 動(dòng)畫的方式彈回去。
在這里需要一個(gè) Animation ,再定義一個(gè) runAnimation 方法,同時(shí)為 第一步創(chuàng)建的動(dòng)畫控制器添加一個(gè)更新監(jiān)聽(tīng)。
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(); } }
然后在手指抬起的時(shí)候,執(zhí)行動(dòng)畫,將被移動(dòng)的 Widget (如這里的圖片)以動(dòng)畫的方式移動(dòng)回原位:
@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.計(jì)算速度以模擬彈簧運(yùn)動(dòng)
最后一步是做一些數(shù)學(xué)運(yùn)算,計(jì)算小部件完成拖動(dòng)后的速度。這是為了使小部件在被拍回之前能夠以這種速度逼真地繼續(xù)。(_runAnimation方法已經(jīng)通過(guò)設(shè)置動(dòng)畫的開(kāi)始和結(jié)束對(duì)齊來(lái)設(shè)置方向。)
導(dǎo)入包如下:
import 'package:flutter/physics.dart';
onPanEnd回調(diào)提供了一個(gè)DragEndDetails對(duì)象。此對(duì)象提供指針停止接觸屏幕時(shí)的速度。速度以像素每秒為單位,但Align小部件不使用像素。它使用介于[-1.0,-1.0]和[1.0,1.0]之間的坐標(biāo)值,其中[0.0,0.0]表示中心。步驟2中計(jì)算的大小用于將像素轉(zhuǎn)換為該范圍內(nèi)的坐標(biāo)值。
然后修改 runAnimation 執(zhí)行動(dòng)畫函數(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ì)量和剛度等屬性,從而實(shí)現(xiàn)更加真實(shí)的動(dòng)畫效果。 const spring = SpringDescription( mass: 30, stiffness: 1, damping: 1, ); //SpringSimulation用來(lái)模擬一個(gè)彈簧的運(yùn)動(dòng),可以用于創(chuàng)建具有彈性的動(dòng)畫效果。 final simulation = SpringSimulation(spring, 0, 1, -unitVelocity); _controller.animateWith(simulation); }
然后在手指抬起的時(shí)候調(diào)用
onPanEnd: (details) { _runAnimation(details.velocity.pixelsPerSecond, size); },
以上就是Android Flutter實(shí)現(xiàn)彈簧動(dòng)畫交互的示例詳解的詳細(xì)內(nèi)容,更多關(guān)于Android Flutter彈簧動(dòng)畫交互的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
解決Could not find com.android.tools.build:gradle:3.0.0
這篇文章主要介紹了在Android Studio升級(jí)時(shí)碰到Could not find com.android.tools.build:gradle:3.0.0問(wèn)題的解決方法,需要的朋友跟隨小編一起看看吧2021-08-08Android實(shí)現(xiàn)開(kāi)機(jī)自動(dòng)啟動(dòng)Service或app的方法
這篇文章主要介紹了Android實(shí)現(xiàn)開(kāi)機(jī)自動(dòng)啟動(dòng)Service或app的方法,結(jié)合實(shí)例形式分析了Android開(kāi)機(jī)自啟動(dòng)程序的具體步驟與相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2016-07-07Android獲取設(shè)備CPU核數(shù)、時(shí)鐘頻率以及內(nèi)存大小的方法
這篇文章主要介紹了Android獲取設(shè)備CPU核數(shù)、時(shí)鐘頻率以及內(nèi)存大小的方法,涉及Android針對(duì)系統(tǒng)硬件相關(guān)操作技巧,需要的朋友可以參考下2016-07-07Android 動(dòng)態(tài)改變布局實(shí)例詳解
這篇文章主要介紹了Android 動(dòng)態(tài)改變布局實(shí)例詳解的相關(guān)資料,這里舉例說(shuō)明如何實(shí)現(xiàn)動(dòng)態(tài)改變布局的例子,幫助大家學(xué)習(xí)理解,需要的朋友可以參考下2016-11-11Android 中 退出多個(gè)activity的經(jīng)典方法
這篇文章主要介紹了Android 中 退出多個(gè)activity的經(jīng)典方法 的相關(guān)資料,本文給大家分享兩種方法,在這小編給大家推薦使用第一種方法,對(duì)此文感興趣的朋友可以參考下2016-09-09實(shí)例講解Android應(yīng)用開(kāi)發(fā)中Fragment生命周期的控制
這篇文章主要介紹了Android應(yīng)用開(kāi)發(fā)中Fragment生命周期的控制,Fragment依賴于Activity,所以生命周期方面也受Activity的影響,需要的朋友可以參考下2016-02-02Android 編輯頭像功能簡(jiǎn)單實(shí)現(xiàn)實(shí)例(圖片選取,裁剪)
這篇文章主要介紹了Android 編輯頭像功能簡(jiǎn)單實(shí)現(xiàn)實(shí)例(圖片選取,裁剪),非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-06-06