日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

Flutter實現抽屜動畫_Android

作者:Android-until ? 更新時間: 2022-05-26 編程語言

這篇會深化View拖拽實例,利用Flutter Animation、插值器以及AnimatedBuilder教大家實現帶動畫的抽屜效果。先來看效果:

通過構思,我們可以設想到實現抽屜的方式就是用Stack控件將兩個Widget疊加顯示,用GestureDetector監聽手勢滑動,動態移動頂層的Widget,當監聽到手勢結束的時候根據手勢滑動的距離動態將頂部Widget利用動畫效果滑動到結束位置即可。

實現底部Widget

class DownDrawerWidget extends StatelessWidget {
? @override
? Widget build(BuildContext context) {
? ? return Container(child: Center(child: Text("底部Widget",),),);
? }
}

這個Widget太簡單了,就不細說了。

實現頂部Widget

class UpDrawerWidget extends StatelessWidget {
? @override
? Widget build(BuildContext context) {
? ? return Container(child: Center(child: Text("頂部Widget",),),);
? }
}

實現方式和底部是一樣的。

實現可以移動的容器

上面兩個Widget都是單純用來顯示的Widget,因此繼承了StatelessWidget。接下來我們需要根據手勢動態移動頂部的Widget,因此需要繼承StatefulWidget。

// 頂部Widget
class HomePageWidget extends StatefulWidget {
? @override
? State createState() => HomePageState();
}

class HomePageState extends State
? ? with SingleTickerProviderStateMixin {

? @override
? void initState() {...}

? @override
? void dispose() {...}

? @override
? Widget build(BuildContext context) {...}

? void _onViewDragDown(DragDownDetails callback) {...}

? void _onViewDrag(DragUpdateDetails callback) {...}

? void _onViewDragUp(DragEndDetails callback) {...}
}

初始化狀態initState()

這個方法是在Widget初始化的時候系統的回調函數,我們需要在該函數中初始化動畫

AnimationController controller;
@override
void initState() {
? ? // 初始化動畫控制器,這里限定動畫時常為200毫秒
? ? controller = new AnimationController(vsync: this, duration: const Duration(milliseconds: 200));
? ? // vsync對象會綁定動畫的定時器到一個可視的widget,所以當widget不顯示時,動畫定時器將會暫停,當widget再次顯示時,動畫定時器重新恢復執行,這樣就可以避免動畫相關UI不在當前屏幕時消耗資源。
? ? // 當使用vsync: this的時候,State對象必須with SingleTickerProviderStateMixin或TickerProviderStateMixin;TickerProviderStateMixin適用于多AnimationController的情況。

? ? // 設置動畫曲線,就是動畫插值器
? ? // 通過這個鏈接可以了解更多差值器,https://docs.flutter.io/flutter/animation/Curves-class.html,我們這里使用帶回彈效果的bounceOut。
? ? CurvedAnimation curve =
? ? ? ? new CurvedAnimation(parent: controller, curve: Curves.bounceOut);

? ? // 增加動畫監聽,當手勢結束的時候通過動態計算到達目標位置的距離實現動畫效果。curve.value為當前動畫的值,取值范圍0~1。
? ? curve.addListener(() {
? ? ? double animValue = curve.value;
? ? ? double offset = dragUpDownX - dragDownX;
? ? ? double toPosition;

? ? ? // 右滑
? ? ? if (offset > 0) {
? ? ? ? if (offset > maxDragX / 5) {
? ? ? ? ? // 打開
? ? ? ? ? toPosition = maxDragX;
? ? ? ? ? isOpenState = true;
? ? ? ? } else {
? ? ? ? ? if (isOpenState) {
? ? ? ? ? ? toPosition = maxDragX;
? ? ? ? ? ? isOpenState = true;
? ? ? ? ? } else {
? ? ? ? ? ? toPosition = 0.0;
? ? ? ? ? ? isOpenState = false;
? ? ? ? ? }
? ? ? ? }
? ? ? } else {
? ? ? ? if (offset < (-maxDragX / 2.0)) {
? ? ? ? ? // 關
? ? ? ? ? toPosition = 0.0;
? ? ? ? ? isOpenState = false;
? ? ? ? } else {
? ? ? ? ? if (isOpenState) {
? ? ? ? ? ? toPosition = maxDragX;
? ? ? ? ? ? isOpenState = true;
? ? ? ? ? } else {
? ? ? ? ? ? toPosition = 0.0;
? ? ? ? ? ? isOpenState = false;
? ? ? ? ? }
? ? ? ? }
? ? ? }

? ? ? dragOffset = (toPosition - dragUpDownX) * animValue + dragUpDownX;
? ? ? // 刷新位置
? ? ? setState(() {});
? ? });
? }

結束Widget dispose()

當Widget不可用將被回收的時候,系統會回調dispose()方法,我們在這里回收動畫。

@override
void dispose() {
? ? controller.dispose();
}

記錄按下的位置

double dragDownX = 0.0;
? void _onViewDragDown(DragDownDetails callback) {
? ? dragDownX = callback.globalPosition.dx;
? }

拖動的時候刷新View的位置

/**
? ?* 最大可拖動位置
? ?*/
? final double maxDragX = 230.0;
? double dragOffset = 0.0;
? void _onViewDrag(DragUpdateDetails callback) {
? ? double tmpOffset = callback.globalPosition.dx - dragDownX;

? ? if (tmpOffset < 0) {
? ? ? tmpOffset += maxDragX;
? ? }

? ? // 邊緣檢測
? ? if (tmpOffset < 0) {
? ? ? tmpOffset = 0.0;
? ? } else if (tmpOffset >= maxDragX) {
? ? ? tmpOffset = maxDragX;
? ? }

? ? // 刷新
? ? if (dragOffset != tmpOffset) {
? ? ? dragOffset = tmpOffset;
? ? ? setState(() {});
? ? }
? }

離手的時候記錄位置并執行動畫

/**
? ?* 脫手時候的位置
? ?*/
? double dragUpDownX = 0.0;
? void _onViewDragUp(DragEndDetails callback) {
? ? dragUpDownX = dragOffset;
? ? // 執行動畫,每次都從第0幀開始執行
? ? controller.forward(from: 0.0);
? }

支持移動的Widget

@override
? Widget build(BuildContext context) {
? ? return Transform.translate(
? ? ? offset: Offset(dragOffset, 0.0),
? ? ? child: Container(
? ? ? ? child: GestureDetector(
? ? ? ? ? ? ? onHorizontalDragDown: _onViewDragDown,
? ? ? ? ? ? ? onVerticalDragDown: _onViewDragDown,
? ? ? ? ? ? ? onHorizontalDragUpdate: _onViewDrag,
? ? ? ? ? ? ? onVerticalDragUpdate: _onViewDrag,
? ? ? ? ? ? ? onHorizontalDragEnd: _onViewDragUp,
? ? ? ? ? ? ? onVerticalDragEnd: _onViewDragUp,
? ? ? ? ? ? ? child: Container(
? ? ? ? ? ? ? ? child: new UpDrawerWidget(),
? ? ? ? ? ),),),);}

Flutter動畫

總結一下,想在Flutter中實現動畫,需要先創建一個AnimationController控制器;如果有特殊的插值要求,再創建一個插值器,調用controller.forward()方法執行動畫,通過addListener()的回調改變對應數值之后調用setState(() {})方法刷新位置即可。

Flutter API還提供AnimatedBuilder用來簡化實現動畫的復雜性,讓我們不用手動調用addListener()方法。

原文鏈接:https://blog.csdn.net/weixin_44339238/article/details/98969379

欄目分類
最近更新