Android?Flutter實現(xiàn)任意拖動的控件
前言
使用flutter開發(fā)是需要控件能拖動,比如畫板中的元素,或者工具條,搜索框,每個都單獨去實現(xiàn)拖動還是比較麻煩的,將拖動功能封裝成一個控件,需要的時候直接使用拖動控件作為父控件這樣就方便很多了。
一、如何實現(xiàn)
1、使用GestureDetector響應拖動事件
//總位移 var _unlimtedOffset = Offset.zero; //當前位移(有活動區(qū)域限制時,鼠標超過邊界后當前位移不等于總位移,此時總位移可以確?;氐竭吔鐑仁髽伺c控件的相對位置不變) final _offset = ValueNotifier<Offset>(Offset.zero); GestureDetector( child: this.widget.child, onPanUpdate: (detail) { //累加拖動距離 _unlimtedOffset += detail.delta; } )
2、使用Transform變換控件位置
使用translate變換位置即可
//ValueListenableBuilder監(jiān)聽_offset 改變,此處略 Transform.translate( offset: offset, child:GestureDetector()//上一步的child:GestureDetector )
3、計算拖動區(qū)域
這一步不是必須的,但是如果需要限制控件活動范圍則需要這一步。
通過GlobalKey獲取控件大小,在GestureDetector的onPanUpdate事件中:
onPanUpdate: (detail) { //拖動區(qū)域為父控件,去掉則不受限制,但拖出父控件會被遮擋無法點擊。 //獲取父控件大小 RenderBox ? parentRenderBox = _mykey.currentContext ? .findAncestorRenderObjectOfType<RenderObject>() as RenderBox ? ; final screenSize = parentRenderBox ? .size; //獲取控件大小 final mySize = _mykey.currentContext ? .size; final renderBox = _mykey.currentContext ? .findRenderObject() as RenderBox ? ; //獲取控件當前位置 var originOffset = renderBox ? .localToGlobal(Offset.zero); if (originOffset != null) { originOffset = parentRenderBox ? .globalToLocal(originOffset); } if (screenSize == null || mySize == null || originOffset == null) { return; } //計算不超出父控件區(qū)域 if (off.dx < -originOffset.dx) { off = Offset(-originOffset.dx, off.dy); } else if (off.dx > screenSize.width - mySize.width - originOffset.dx) { off = Offset( screenSize.width - mySize.width - originOffset.dx, off.dy, ); } if (off.dy < -originOffset.dy) { off = Offset(off.dx, -originOffset.dy); } else if (off.dy > screenSize.height - mySize.height - originOffset.dy) { off = Offset( off.dx, screenSize.height - mySize.height - originOffset.dy, ); } //現(xiàn)在活動區(qū)域為父控件 --end }
二、完整代碼
drag_move_box.dart
import 'package:flutter/material.dart'; /// 可拖動容器 /// 拖動范圍是父控件 class DragMoveBox extends StatefulWidget { final Widget child; const DragMoveBox({ super.key, required this.child, }); @override State<DragMoveBox> createState() => _DragMoveBoxState(); } class _DragMoveBoxState extends State<DragMoveBox> { final GlobalKey _mykey = GlobalKey(); //當前位移(有活動區(qū)域限制時,鼠標超過邊界后當前位移不等于總位移,此時總位移可以確?;氐竭吔鐑仁髽伺c控件的相對位置不變) final _offset = ValueNotifier<Offset>(Offset.zero); //總位移 var _unlimtedOffset = Offset.zero; @override Widget build(BuildContext context) { return ValueListenableBuilder( valueListenable: _offset, builder: //采用transform變換實現(xiàn)拖動 (context, offset, widget) => Transform.translate( key: _mykey, offset: offset, child: GestureDetector( child: this.widget.child, onPanUpdate: (detail) { var off = _unlimtedOffset = _unlimtedOffset + detail.delta; //拖動區(qū)域為父控件,去掉則不受限制,但拖出父控件會被遮擋無法點擊。 //獲取父控件大小 RenderBox? parentRenderBox = _mykey.currentContext ?.findAncestorRenderObjectOfType<RenderObject>() as RenderBox?; final screenSize = parentRenderBox?.size; //獲取控件大小 final mySize = _mykey.currentContext?.size; final renderBox = _mykey.currentContext?.findRenderObject() as RenderBox?; //獲取控件當前位置 var originOffset = renderBox?.localToGlobal(Offset.zero); if (originOffset != null) { originOffset = parentRenderBox?.globalToLocal(originOffset); } if (screenSize == null || mySize == null || originOffset == null) { return; } //計算不超出父控件區(qū)域 if (off.dx < -originOffset.dx) { off = Offset(-originOffset.dx, off.dy); } else if (off.dx > screenSize.width - mySize.width - originOffset.dx) { off = Offset( screenSize.width - mySize.width - originOffset.dx, off.dy, ); } if (off.dy < -originOffset.dy) { off = Offset(off.dx, -originOffset.dy); } else if (off.dy > screenSize.height - mySize.height - originOffset.dy) { off = Offset( off.dx, screenSize.height - mySize.height - originOffset.dy, ); } //現(xiàn)在活動區(qū)域為父控件 --end _offset.value = off; }, ), ), ); } }
三、使用示例
1、基本用法
DragMoveBox( child:Text("You have pushed the button this many times:") //需要拖動的控件 )
2.效果預覽
總結
本文提供了一種簡單的拖動控件實現(xiàn),尤其是封裝成容器后使用變得很簡單,主要在于能想到translate變換可以改變位置,在了解通過GlobalKey獲取控件大小以及獲取控件大小的方法,很容易就實現(xiàn)拖動功能了。
以上就是Android Flutter實現(xiàn)任意拖動的控件的詳細內容,更多關于Android Flutter任意拖動控件的資料請關注腳本之家其它相關文章!
相關文章
Android布局技巧之include、merge與ViewStub標簽的巧用
Android 官方提供了三個用來優(yōu)化布局的標簽,分別是include、merge與ViewStub,下面這篇文章主要給大家介紹了關于Android布局技巧之include、merge與ViewStub標簽巧用的相關資料,需要的朋友可以參考下2018-06-06android 之Spinner下拉菜單實現(xiàn)級聯(lián)
android 之Spinner下拉菜單實現(xiàn)級聯(lián),需要的朋友可以參考一下2013-02-02Android App實現(xiàn)監(jiān)聽軟鍵盤按鍵的三種方式
本篇文章主要介紹Android App實現(xiàn)監(jiān)聽軟鍵盤按鍵的三種方式,具有一定的參考價值,感興趣的小伙伴們可以參考一下。2017-03-03