最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android?Flutter實(shí)現(xiàn)任意拖動(dòng)的控件

 更新時(shí)間:2023年07月02日 09:57:48   作者:CodeOfCC  
使用flutter開(kāi)發(fā)是需要控件能拖動(dòng),比如畫(huà)板中的元素,或者工具條等,所以本文為大家準(zhǔn)備了Flutter實(shí)現(xiàn)任意拖動(dòng)控件的示例代碼,希望對(duì)大家有所幫助

前言

使用flutter開(kāi)發(fā)是需要控件能拖動(dòng),比如畫(huà)板中的元素,或者工具條,搜索框,每個(gè)都單獨(dú)去實(shí)現(xiàn)拖動(dòng)還是比較麻煩的,將拖動(dòng)功能封裝成一個(gè)控件,需要的時(shí)候直接使用拖動(dòng)控件作為父控件這樣就方便很多了。

一、如何實(shí)現(xiàn)

1、使用GestureDetector響應(yīng)拖動(dòng)事件

//總位移
var _unlimtedOffset = Offset.zero;
//當(dāng)前位移(有活動(dòng)區(qū)域限制時(shí),鼠標(biāo)超過(guò)邊界后當(dāng)前位移不等于總位移,此時(shí)總位移可以確?;氐竭吔鐑?nèi)鼠標(biāo)與控件的相對(duì)位置不變)
final _offset = ValueNotifier<Offset>(Offset.zero);
GestureDetector(
  child: this.widget.child,
   onPanUpdate: (detail) {
       //累加拖動(dòng)距離
      _unlimtedOffset += detail.delta;
 }
)

2、使用Transform變換控件位置

使用translate變換位置即可

//ValueListenableBuilder監(jiān)聽(tīng)_offset 改變,此處略
Transform.translate(
    offset: offset,
    child:GestureDetector()//上一步的child:GestureDetector
)

3、計(jì)算拖動(dòng)區(qū)域

這一步不是必須的,但是如果需要限制控件活動(dòng)范圍則需要這一步。

通過(guò)GlobalKey獲取控件大小,在GestureDetector的onPanUpdate事件中:

onPanUpdate: (detail) {
   //拖動(dòng)區(qū)域?yàn)楦缚丶サ魟t不受限制,但拖出父控件會(huì)被遮擋無(wú)法點(diǎn)擊。
   //獲取父控件大小
   RenderBox ? parentRenderBox = _mykey.currentContext
   ? .findAncestorRenderObjectOfType<RenderObject>() as RenderBox ? ;
   final screenSize = parentRenderBox ? .size;
   //獲取控件大小
   final mySize = _mykey.currentContext ? .size;
   final renderBox =
   _mykey.currentContext ? .findRenderObject() as RenderBox ? ;
   //獲取控件當(dāng)前位置    
   var originOffset = renderBox ? .localToGlobal(Offset.zero);
   if (originOffset != null) {
   	originOffset = parentRenderBox ? .globalToLocal(originOffset);
   }
   if (screenSize == null || mySize == null || originOffset == null) {
   	return;
   }
   //計(jì)算不超出父控件區(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)在活動(dòng)區(qū)域?yàn)楦缚丶?--end
}

二、完整代碼

drag_move_box.dart

import 'package:flutter/material.dart';
/// 可拖動(dòng)容器
/// 拖動(dòng)范圍是父控件
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();
  //當(dāng)前位移(有活動(dòng)區(qū)域限制時(shí),鼠標(biāo)超過(guò)邊界后當(dāng)前位移不等于總位移,此時(shí)總位移可以確?;氐竭吔鐑?nèi)鼠標(biāo)與控件的相對(duì)位置不變)
  final _offset = ValueNotifier<Offset>(Offset.zero);
  //總位移
  var _unlimtedOffset = Offset.zero;
  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder(
      valueListenable: _offset,
      builder:
          //采用transform變換實(shí)現(xiàn)拖動(dòng)
          (context, offset, widget) => Transform.translate(
        key: _mykey,
        offset: offset,
        child: GestureDetector(
          child: this.widget.child,
          onPanUpdate: (detail) {
            var off = _unlimtedOffset = _unlimtedOffset + detail.delta;
            //拖動(dòng)區(qū)域?yàn)楦缚丶?,去掉則不受限制,但拖出父控件會(huì)被遮擋無(wú)法點(diǎn)擊。
            //獲取父控件大小
            RenderBox? parentRenderBox = _mykey.currentContext
                ?.findAncestorRenderObjectOfType<RenderObject>() as RenderBox?;
            final screenSize = parentRenderBox?.size;
            //獲取控件大小
            final mySize = _mykey.currentContext?.size;
            final renderBox =
                _mykey.currentContext?.findRenderObject() as RenderBox?;
            //獲取控件當(dāng)前位置    
            var originOffset = renderBox?.localToGlobal(Offset.zero);
            if (originOffset != null) {
              originOffset = parentRenderBox?.globalToLocal(originOffset);
            }
            if (screenSize == null || mySize == null || originOffset == null) {
              return;
            }
            //計(jì)算不超出父控件區(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)在活動(dòng)區(qū)域?yàn)楦缚丶?--end
            _offset.value = off;
          },
        ),
      ),
    );
  }
}

三、使用示例

1、基本用法

DragMoveBox(
child:Text("You have pushed the button this many times:") //需要拖動(dòng)的控件
)

2.效果預(yù)覽

總結(jié)

本文提供了一種簡(jiǎn)單的拖動(dòng)控件實(shí)現(xiàn),尤其是封裝成容器后使用變得很簡(jiǎn)單,主要在于能想到translate變換可以改變位置,在了解通過(guò)GlobalKey獲取控件大小以及獲取控件大小的方法,很容易就實(shí)現(xiàn)拖動(dòng)功能了。

以上就是Android Flutter實(shí)現(xiàn)任意拖動(dòng)的控件的詳細(xì)內(nèi)容,更多關(guān)于Android Flutter任意拖動(dòng)控件的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論

武安市| 连南| 恩平市| 武胜县| 饶平县| 柳河县| 桑日县| 永新县| 辽阳县| 孙吴县| 公主岭市| 榕江县| 南开区| 武平县| 泰宁县| 肥东县| 福州市| 英吉沙县| 桑日县| 长岭县| 康保县| 宝山区| 衡水市| 嘉兴市| 眉山市| 临高县| 裕民县| 垣曲县| 台湾省| 射阳县| 金溪县| 大城县| 阳城县| 南康市| 玉山县| 吴江市| 天峨县| 临江市| 屏东市| 兴仁县| 永新县|