欢迎访问移动开发之家(rcyd.net),关注移动开发教程。移动开发之家  移动开发问答|  每日更新
页面位置 : > > > 内容正文

Android Flutter实现任意拖动的控件,

来源: 开发者 投稿于  被查看 49890 次 评论:137

Android Flutter实现任意拖动的控件,


目录
  • 前言
  • 一、如何实现
    • 1、使用GestureDetector响应拖动事件
    • 2、使用Transform变换控件位置
    • 3、计算拖动区域
  • 二、完整代码
    • 三、使用示例
      • 1、基本用法
      • 2.效果预览
    • 总结

      前言

      使用flutter开发是需要控件能拖动,比如画板中的元素,或者工具条,搜索框,每个都单独去实现拖动还是比较麻烦的,将拖动功能封装成一个控件,需要的时候直接使用拖动控件作为父控件这样就方便很多了。

      一、如何实现

      1、使用GestureDetector响应拖动事件

      //总位移
      var _unlimtedOffset = Offset.zero;
      //当前位移(有活动区域限制时,鼠标超过边界后当前位移不等于总位移,此时总位移可以确保回到边界内鼠标与控件的相对位置不变)
      final _offset = ValueNotifier<Offset>(Offset.zero);
      GestureDetector(
        child: this.widget.child,
         onPanUpdate: (detail) {
             //累加拖动距离
            _unlimtedOffset += detail.delta;
       }
      )

      2、使用Transform变换控件位置

      使用translate变换位置即可

      //ValueListenableBuilder监听_offset 改变,此处略
      Transform.translate(
          offset: offset,
          child:GestureDetector()//上一步的child:GestureDetector
      )

      3、计算拖动区域

      这一步不是必须的,但是如果需要限制控件活动范围则需要这一步。

      通过GlobalKey获取控件大小,在GestureDetector的onPanUpdate事件中:

      onPanUpdate: (detail) {
         //拖动区域为父控件,去掉则不受限制,但拖出父控件会被遮挡无法点击。
         //获取父控件大小
         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;
         }
         //计算不超出父控件区域
         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,
         		);
         }
         //现在活动区域为父控件 --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();
        //当前位移(有活动区域限制时,鼠标超过边界后当前位移不等于总位移,此时总位移可以确保回到边界内鼠标与控件的相对位置不变)
        final _offset = ValueNotifier<Offset>(Offset.zero);
        //总位移
        var _unlimtedOffset = Offset.zero;
        @override
        Widget build(BuildContext context) {
          return ValueListenableBuilder(
            valueListenable: _offset,
            builder:
                //采用transform变换实现拖动
                (context, offset, widget) => Transform.translate(
              key: _mykey,
              offset: offset,
              child: GestureDetector(
                child: this.widget.child,
                onPanUpdate: (detail) {
                  var off = _unlimtedOffset = _unlimtedOffset + detail.delta;
                  //拖动区域为父控件,去掉则不受限制,但拖出父控件会被遮挡无法点击。
                  //获取父控件大小
                  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;
                  }
                  //计算不超出父控件区域
                  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,
                    );
                  }
                  //现在活动区域为父控件 --end
                  _offset.value = off;
                },
              ),
            ),
          );
        }
      }

      三、使用示例

      1、基本用法

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

      2.效果预览

      总结

      本文提供了一种简单的拖动控件实现,尤其是封装成容器后使用变得很简单,主要在于能想到translate变换可以改变位置,在了解通过GlobalKey获取控件大小以及获取控件大小的方法,很容易就实现拖动功能了。

      以上就是Android Flutter实现任意拖动的控件的详细内容,更多关于Android Flutter任意拖动控件的资料请关注3672js教程其它相关文章!

      您可能感兴趣的文章:
      • Android实现控件拖动效果
      • android控件实现单击拖动效果
      • Android如何创建可拖动的图片控件
      • Android控件拖动实例详解
      • Android编程之控件可拖动的实现方法
      • Android实现view拖动到任意位置
      • Android 实现可任意拖动的悬浮窗功能(类似悬浮球)

      用户评论