如何避免Stack中Matrix4 Transform可拖拽组件新增子部件时位置重置
问题根源
- 拖拽状态没有持久化存储:你将控制位置缩放的
Matrix4存在Drag组件内部的局部ValueNotifier中,每次点击新增按钮触发DummyProvider的notifyListeners后,上层MyApp组件重绘,所有Drag组件都会被重建,内部的ValueNotifier会重置为单位矩阵,自然就回到了屏幕初始位置。 - 状态没有和数据绑定:你在
DraggableText类中已经预留了position字段用于存储位置变换,但实际开发中没有用到,既没有在初始化Drag组件时读取这个字段的取值,也没有在拖拽过程中将最新的变换矩阵同步到这个字段中。 - 列表子组件缺少唯一标识:
Stack的子组件列表动态更新时,没有给每个Drag组件绑定唯一Key,会导致Flutter框架复用组件时出现状态错位。
修复步骤
1. 扩展DummyProvider增加更新位置的方法
class DummyProvider extends ChangeNotifier { List<DraggableText> list = []; String currentText = ''; void addToList(DraggableText text) { list.add(text); notifyListeners(); } // 新增更新指定拖拽组件位置的方法 void updatePosition(String id, Matrix4 newPosition) { final index = list.indexWhere((element) => element.id == id); if (index != -1) { list[index].position = newPosition; // 如果不需要拖拽时实时触发其他组件更新,可以去掉这里的notifyListeners,降低重绘开销 // notifyListeners(); } } }
2. 改造Drag组件,绑定数据状态
// 组件参数增加对应DraggableText实例和provider实例 class Drag extends StatelessWidget { final DraggableText draggableText; final DummyProvider provider; const Drag({super.key, required this.draggableText, required this.provider}); @override Widget build(BuildContext context) { // 初始化时读取已存储的位置,不再默认用单位矩阵 final ValueNotifier<Matrix4> notifier = ValueNotifier(draggableText.position); return MatrixGestureDetector( onMatrixUpdate: (m, tm, sm, rm) { notifier.value = m; // 拖拽时同步更新provider中存储的位置 provider.updatePosition(draggableText.id, m); }, child: AnimatedBuilder( animation: notifier, builder: (ctx, child) { return Transform( transform: notifier.value, child: Center( child: Stack( children: <Widget>[ Transform.scale( scale: 1, origin: const Offset(0.0, 0.0), child: GestureDetector( child: Container( color: Colors.blueAccent, child: Text(draggableText.text, style: const TextStyle(fontSize: 40)) ) ), ), ], ), ), ); }, ), ); } }
3. 修改MyApp中Stack子组件生成逻辑,增加唯一Key
child: Stack( children: List.generate( dummyProvider.list.length, (index) => Drag( // 绑定唯一Key避免组件复用错位 key: Key(dummyProvider.list[index].id), draggableText: dummyProvider.list[index], provider: dummyProvider, ) ), ),
内容的提问来源于stack exchange,提问作者lucifer
相关产品推荐
相关产品推荐

