Flutter 实现任意控件拖动

文章目录

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


前言

使用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,});State<DragMoveBox> createState() => _DragMoveBoxState();
}class _DragMoveBoxState extends State<DragMoveBox> {final GlobalKey _mykey = GlobalKey();//当前位移(有活动区域限制时,鼠标超过边界后当前位移不等于总位移,此时总位移可以确保回到边界内鼠标与控件的相对位置不变)final _offset = ValueNotifier<Offset>(Offset.zero);//总位移var _unlimtedOffset = Offset.zero;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:") //需要拖动的控件
)

效果预览
在这里插入图片描述


总结

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/7601.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

arcgis api for JavaScript4.2x 在vue中白膜图层的加载、(分类、分段)渲染

这篇文章是对有webgis前端开发经验的人 1、假设之前的三维视图均已成功加载&#xff0c;获取到了三维视图&#xff0c;这里的三维视图变量定义的名字是mapView。&#xff08;PS&#xff1a;三维视图mapview在项目初始化已经设置了&#xff0c;本示例中会直接使用调用结果&…

Unity 热力图效果实现 笔记

Unity 热力图效果实现 笔记 参考文献连接&#xff1a; 1、人体热力图shader graph实现&#xff08;URP&#xff09; 超链接&#xff1a; https://www.youtube.com/watch?vKlMON4Dzq_0&t51s shader forge 翻译通用管线下 连接点实现方案&#xff1a; 2、碰撞热力图实现…

【python爬虫应用03】csdn个人所有文章质量分查询

&#x1f6e0;️ 环境准备 在开始编写代码之前&#xff0c;我们需要进行一些环境准备。以下是所需的环境和库&#xff1a; 操作系统&#xff1a;Windows编程语言&#xff1a;Python 3编辑器&#xff1a;VSCode&#xff08;可选&#xff09; 安装所需的库&#xff1a; reque…

php宝塔搭建EMLOG站长工具箱网站自适应PC手机端php源码

大家好啊&#xff0c;我是测评君&#xff0c;欢迎来到web测评。本期给大家带来一套站长工具箱网站自适应PC手机端php源码。感兴趣的朋友可以自行下载学习。 技术架构 PHP5.6 nginx mysql5.6 JS CSS HTMLcnetos7以上 宝塔面板 文字搭建教程 下载源码&#xff0c;宝塔添…

Spring Cloud

一、微服务架构 单体架构&#xff1a;将业务的所有功能集中在一个项 目中开发&#xff0c;打成一个包部署 分布式架构&#xff1a;根据业务功能对系统做拆分&#xff0c; 每个业务功能模块作为独立项目 开发&#xff0c;称为一个服务 微服务架构&#xff1a; 特征&#xff1a; …

CSS样式表

CSS样式表 1、CSS介绍 CSS Cascading Style Sheet 层叠样式表&#xff0c;或&#xff0c;级联样式表 表现HTML文件样式的计算机语言 修饰静态页面 配置脚本语言动态对网页元素进行样式格式化 排序 对元素的位置进行像素级精确控制 支持所有字体字号样式 对网页对象和模型样式…

springboot集成camunda

1、相关软件下载Camunda流程引擎快速入门——Hello World示例 2、由于camunda-modeler最新版本为5.12.0.界面不太一样。 可以安装历史版本4.12.0camunda-bpm camunda-modeler等历史版本下载 3、汉化Camunda Modeler汉化添加简体中文和繁体中文支持 4、集成如何实现Springbootca…

LVS负载均衡集群

目录 1.LVS 2.集群分类 3.负载均衡集群工作模式 4.负载均衡集群架构 5.LVS作用 6.LVS与nginx比较 7.ipvsadm工具 8.实验 第一台服务器 进入第二台第三台服务器下载http服务nfs服务rpcbind服务并启动 进入第四台服务器 9.总结 1.LVS 负载均衡的结构 2.集群分类 负载均衡…

Java基础---String str=new String(“tang“)创建了几个对象

目录 典型回答 常量池基本概念 字符串常量池的结构 再看字面量和运行时常量池 intern 还是创建了几个对象 intern的正确用法 典型回答 创建的对象数应该是1个或者2个如果常量池中存在&#xff0c;则直接new一个对象如果常量池不存在&#xff0c;则在常量池中创建一个对象…

MySQL数据库——MHA高可用

MySQL数据库——MHA高可用 一、MHA概述1&#xff0e;什么是 MHA2&#xff0e;MHA 的组成3&#xff0e;MHA 的特点 二、搭建 MySQL MHA1.Master、Slave1、Slave2 节点上安装 mysql5.72&#xff0e;修改 Master、Slave1、Slave2 节点的主机名&#xff0c;添加主从mysql的映射关系…

select……for update 到底加的什么锁

先上结论 主键索引唯一索引普通索引普通字段等值查询行锁行锁行锁间隙锁&#xff0c;锁表范围查询间隙锁&#xff0c;锁范围行间隙锁&#xff0c;锁范围行间隙锁&#xff0c;锁范围行间隙锁&#xff0c;锁表 数据表准备 DROP TABLE IF EXISTS t_user_test; CREATE TABLE t_u…

七牛云下载文件(显示在浏览器上)

最近在做关于如何将七牛云的文件下载下来&#xff0c;且在浏览器页面展示下载文件。 首先&#xff0c;我们需要注册七牛云账号 七牛云官网。 选择个人账户即可&#xff0c;若是需要企业账户&#xff0c;则可以选择企业账户。 注册成功绑定邮箱后&#xff0c;我们可以创建存储…