Flutter:Bottom Sheet打开时如何通过手势移动替代容器
Flutter 替代容器拖动功能修复
你的代码里有个逻辑错误导致BottomSheet打开时替代容器无法拖动:替代容器的onPanUpdate里写反了判断条件,当_showAlternateContainer为true(也就是替代容器显示时),反而不会执行拖动逻辑。
具体问题点
在替代容器的GestureDetector中:
onPanUpdate: (details) { if (!_showAlternateContainer) { // 这里条件写反了! setState(() { top += details.delta.dy; left += details.delta.dx; print("container move"); }); } },
当替代容器显示时,_showAlternateContainer是true,所以!_showAlternateContainer为false,拖动逻辑根本不会执行。
修复方案
- 移除错误的条件判断,直接在
onPanUpdate中更新位置 - 添加
onPanDown事件,保持和原图片容器一致的选中状态逻辑,确保拖动时容器处于选中状态
修复后的完整代码如下:
import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; // 假设GlobalState是你定义的全局状态类 class GlobalState { static List<MovableImageBox> movableAllWidgets = []; static int selectedIndex = 0; static ValueNotifier<bool> isBottomSheetVisible = ValueNotifier(false); } class MovableImageBox extends StatefulWidget { late final _MovableImageBoxState currentWidget; int index; MovableImageBox({required this.index}); @override _MovableImageBoxState createState() { _MovableImageBoxState currentState = _MovableImageBoxState(); this.currentWidget = currentState; return currentState; } } const ballDiameter = 15.0; const rotateIconSize = 30.0; class _MovableImageBoxState extends State<MovableImageBox> { double width = 300; double height = 200.0; double aspectRatio = 200 / 300; bool _isSelected = true; double top = 100; double left = 100; bool _showAlternateContainer = false; // 补充原代码中调用但未实现的方法 void updateIsSelected(bool value) { setState(() { _isSelected = value; }); } @override void initState() { super.initState(); } @override Widget build(BuildContext context) { return Stack(children: [ Positioned( top: top, left: left, child: GestureDetector( onTap: () { for (var i = 0; i < GlobalState.movableAllWidgets.length; i++) { print("_addMovableTextBox $i"); GlobalState.movableAllWidgets[i].currentWidget .updateIsSelected(false); } setState(() { _isSelected = true; GlobalState.selectedIndex = widget.index; print("index = ${GlobalState.selectedIndex}"); }); }, onPanDown: (details) { print("down time width =$width"); print("down time height =$height"); for (var i = 0; i < GlobalState.movableAllWidgets.length; i++) { print("_addMovableTextBox $i"); GlobalState.movableAllWidgets[i].currentWidget .updateIsSelected(false); } setState(() { FocusScope.of(context).unfocus(); _isSelected = true; }); }, onPanUpdate: (details) { setState(() { top += details.delta.dy; left += details.delta.dx; }); }, onDoubleTap: () { _showBottomSheet(); }, child: Container( height: height, width: width, padding: EdgeInsets.all(2.0), decoration: BoxDecoration( color: Colors.transparent, border: Border.all( width: 2, color: _isSelected ? Colors.black : Colors.transparent, ), ), child: ClipRect( child: Align( alignment: Alignment.topCenter, child: Image.asset( 'images/rose1.png', width: width, height: height, fit: BoxFit.cover, ), ), ), ), ), ), if (_showAlternateContainer) Positioned( top: top, left: left, child: GestureDetector( // 保持选中状态逻辑一致 onPanDown: (details) { for (var i = 0; i < GlobalState.movableAllWidgets.length; i++) { GlobalState.movableAllWidgets[i].currentWidget .updateIsSelected(false); } setState(() { _isSelected = true; }); }, // 移除错误条件,直接执行拖动逻辑 onPanUpdate: (details) { setState(() { top += details.delta.dy; left += details.delta.dx; print("container move"); }); }, child: Container( height: height - 20, width: width - 20, decoration: BoxDecoration( color: Colors.transparent, border: Border.all( width: 2, color: Colors.black, ), ), child: Center( child: Text( 'Alternate Container', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Colors.white, ), ), ), ), ), ), ]); } void _showBottomSheet() { setState(() { GlobalState.isBottomSheetVisible.value = true; _showAlternateContainer = true; }); showModalBottomSheet( context: context, barrierColor: Colors.black.withAlpha(50), builder: (BuildContext context) { return Container( height: 230, child: Center( child: Text("This is a bottom sheet"), ), ); }, ).whenComplete(() { print("${GlobalState.isBottomSheetVisible}"); setState(() { GlobalState.isBottomSheetVisible.value = false; _showAlternateContainer = false; }); print("${GlobalState.isBottomSheetVisible}"); }); } }
额外说明
- 补充了
updateIsSelected方法(原代码中调用但未实现) - 统一了替代容器的边框颜色逻辑,避免冗余判断
- 在替代容器的
onPanDown中添加了选中状态处理,和原图片容器保持一致逻辑
内容的提问来源于stack exchange,提问作者Harsh Rajpara
相关产品推荐
相关产品推荐

