Flutter自定义拖动容器回弹Animation动画仅单次生效问题求解
问题原因
- AnimationController首次调用
forward()执行完动画后会进入completed完成状态,没有重置的情况下后续再次调用forward()不会触发动画执行,是第二次拖动后无回弹的核心原因。 - 原代码把动画实例创建、监听添加的逻辑放到了
onVerticalDragUpdate回调中,拖动过程中每触发一次偏移更新就会重复创建动画、重复添加监听,会导致监听累积触发,引发状态异常和性能损耗。
修复方案
- 拖动更新回调中仅保留高度实时计算修改的逻辑,删除动画相关代码
- 拖动结束回调中先重置动画控制器,再创建对应回弹动画执行
- 单独抽离动画更新高度的监听方法,避免重复添加监听
完整修改后代码
class _HomeViewState extends State<HomeView> with TickerProviderStateMixin { HomeViewController homeController = HomeViewController(); late Animation<double> translateBetween; late AnimationController customAnimationController; @override void initState() { customAnimationController = AnimationController( vsync: this, duration: const Duration(milliseconds: 2000)); super.initState(); } @override void dispose() { customAnimationController.dispose(); super.dispose(); } // 单独抽离动画更新高度的逻辑 void _updateAnimatedHeight() { homeController.animatedHeight = translateBetween.value; } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.black, body: Column( mainAxisAlignment: MainAxisAlignment.end, children: [ Obx(() { return Container( alignment: Alignment.topCenter, child: Column( children: [ GestureDetector( onVerticalDragUpdate: (dragUpdateDetails) { // 仅保留拖动时实时计算高度的逻辑 double newHeight = homeController.animatedHeight - dragUpdateDetails.primaryDelta! / 6.5; // 用clamp做边界限制更简洁 homeController.animatedHeight = newHeight.clamp(20.0, 95.0); }, onVerticalDragEnd: (dragEndDetails) { // 先重置动画控制器,清除上一次的完成状态 customAnimationController.reset(); // 释放时才创建回弹动画,begin为当前高度,end为初始高度20 final tween = Tween<double>( begin: homeController.animatedHeight, end: 20.0); translateBetween = tween.animate(CurvedAnimation( parent: customAnimationController, curve: Curves.bounceOut, )); // 先移除旧监听避免重复触发 translateBetween.removeListener(_updateAnimatedHeight); translateBetween.addListener(_updateAnimatedHeight); // 执行回弹动画 customAnimationController.forward(); }, child: Column( children: [ const Icon(Icons.arrow_upward_rounded), SizedBox( width: 20.w, child: Divider( color: Colors.black, thickness: 0.3.w, ), ), ], ), ), ], ), width: 100.w, height: homeController.animatedHeight.h, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.only( topLeft: Radius.circular(5.w), topRight: Radius.circular(5.w))), ); }) ], ), ); } }
控制器代码无需修改:
class HomeViewController extends GetxController { final RxDouble _animatedHeight = 20.0.obs; double get animatedHeight => _animatedHeight.value; set animatedHeight(double value) => _animatedHeight.value = value; }
内容的提问来源于stack exchange,提问作者Mehmet Karanlık
相关产品推荐
相关产品推荐

