Flutter如何在屏幕点击的指定偏移位置动态创建widget
Flutter 白板点击位置动态创建文本框实现方案
核心实现逻辑基于Stack绝对布局,通过坐标转换拿到点击位置相对于白板容器的偏移,再用Positioned组件把文本框定位到目标位置即可。
1. 前置状态定义
首先定义需要的状态变量:
// 存储白板上所有动态添加的组件 final List<Widget> _boardChildren = []; // 绑定白板Stack容器的key,用于坐标转换 final GlobalKey _boardKey = GlobalKey();
2. 白板容器与点击监听
用Stack作为白板的根容器,外层包GestureDetector监听点击事件,注意必须把点击返回的全局坐标转换成白板容器内部的相对坐标,否则会出现定位偏移:
@override Widget build(BuildContext context) { return Scaffold( body: GestureDetector( key: _boardKey, onTapUp: (tapDetails) { // 获取白板容器的渲染对象 final renderBox = _boardKey.currentContext!.findRenderObject() as RenderBox; // 全局坐标转白板容器内相对坐标 final tapOffset = renderBox.globalToLocal(tapDetails.globalPosition); // 在点击位置插入文本框 _insertTextField(tapOffset); }, child: Stack( key: _boardKey, children: [ // 白板底色 Container( width: double.infinity, height: double.infinity, color: Colors.white, ), // 渲染所有已添加的动态组件 ..._boardChildren, ], ), ), ); }
3. 目标位置插入文本框逻辑
用Positioned包裹文本框组件,把转换后的点击偏移值设为left和top属性即可完成定位:
void _insertTextField(Offset position) { final newTextField = Positioned( left: position.dx, top: position.dy, width: 220, // 固定文本框初始宽度,避免横向撑满 child: TextField( autofocus: true, // 创建后自动聚焦,直接唤起输入 decoration: InputDecoration( border: OutlineInputBorder(), hintText: "请输入内容", filled: true, fillColor: Colors.white, contentPadding: EdgeInsets.all(8), ), ), ); setState(() { _boardChildren.add(newTextField); }); }
可选优化点
- 如果需要点击位置作为文本框的中心点,只需要给
left赋值position.dx - 文本框宽度/2,top赋值position.dy - 文本框预估高度/2即可 - 文本框进入编辑状态时,临时禁用外层
GestureDetector的点击回调,避免输入时误触创建新的文本框 - 需要支持拖动、缩放文本框的话,可以在
Positioned外层包裹手势识别组件,单独处理每个文本框的手势事件,避免和白板层的手势冲突

内容的提问来源于stack exchange,提问作者Kevin Yang
相关产品推荐
相关产品推荐

