Flutter自定义开关联动异常求助:如何实现互斥切换?
Flutter自定义Switch互斥切换UI不同步问题解决
问题场景
使用两个自定义CustomSwitch实现互斥逻辑:切换其中一个开关时,另一个自动切换状态,确保始终只有一个开关处于开启状态。目前变量值已能正确更新,但开关的UI状态无法同步变化,需要在保留自定义Switch的前提下修复该问题。
问题原因
自定义CustomSwitch的内部动画状态仅在initState中初始化,当父组件传递的value属性发生变化时,内部未更新动画的对齐状态和控制器状态,导致UI无法跟随外部变量同步更新。
解决步骤
在_CustomSwitchState类中添加didUpdateWidget方法,当外部传入的value变化时,重新配置动画的起始/结束对齐值,并调整动画控制器的状态,确保UI与外部值同步。
修改后的CustomSwitch代码
library custom_switch; import 'package:flutter/material.dart'; class CustomSwitch extends StatefulWidget { final bool value; final ValueChanged<bool> onChanged; final Color activeColor; final Color inactiveColor; final String activeText; final String inactiveText; final Color activeTextColor; final Color inactiveTextColor; const CustomSwitch({ required this.value, required this.onChanged, required this.activeColor, this.inactiveColor = Colors.grey, this.activeText = '', this.inactiveText = '', this.activeTextColor = Colors.white70, this.inactiveTextColor = Colors.white70, }); @override _CustomSwitchState createState() => _CustomSwitchState(); } class _CustomSwitchState extends State<CustomSwitch> with SingleTickerProviderStateMixin { late Animation _circleAnimation; late AnimationController _animationController; @override void initState() { super.initState(); _animationController = AnimationController(vsync: this, duration: const Duration(milliseconds: 60)); _circleAnimation = AlignmentTween( begin: widget.value ? Alignment.centerRight : Alignment.centerLeft, end: widget.value ? Alignment.centerLeft : Alignment.centerRight, ).animate(CurvedAnimation( parent: _animationController, curve: Curves.linear, )); // 初始化时根据value设置动画状态 if (widget.value) { _animationController.forward(); } else { _animationController.reverse(); } } @override void didUpdateWidget(covariant CustomSwitch oldWidget) { super.didUpdateWidget(oldWidget); // 当外部value变化时更新动画 if (oldWidget.value != widget.value) { // 重新创建动画tween _circleAnimation = AlignmentTween( begin: widget.value ? Alignment.centerRight : Alignment.centerLeft, end: widget.value ? Alignment.centerLeft : Alignment.centerRight, ).animate(CurvedAnimation( parent: _animationController, curve: Curves.linear, )); // 根据新value调整动画控制器状态 if (widget.value) { _animationController.forward(); } else { _animationController.reverse(); } } } @override void dispose() { _animationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return AnimatedBuilder( animation: _animationController, builder: (context, child) { return GestureDetector( onTap: () { if (_animationController.isCompleted) { _animationController.reverse(); } else { _animationController.forward(); } widget.onChanged(!widget.value); }, child: Container( width: 70.0, height: 35.0, decoration: BoxDecoration( borderRadius: BorderRadius.circular(20.0), color: _circleAnimation.value == Alignment.centerLeft ? const Color(0xffD4D4D4) : null, gradient: _circleAnimation.value == Alignment.centerRight ? const LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Color(0xffFF5A5A), Color(0x505AB0FF), ], ) : null, ), child: Padding( padding: const EdgeInsets.only( top: 4.0, bottom: 4.0, right: 4.0, left: 4.0, ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[ _circleAnimation.value == Alignment.centerRight ? Padding( padding: const EdgeInsets.only(left: 34.0, right: 0), child: Text( widget.activeText, style: TextStyle( color: widget.activeTextColor, fontWeight: FontWeight.w900, fontSize: 16.0, ), ), ) : Container(), Align( alignment: _circleAnimation.value, child: Container( width: 25.0, height: 25.0, decoration: const BoxDecoration( shape: BoxShape.circle, color: Colors.white, ), ), ), _circleAnimation.value == Alignment.centerLeft ? Padding( padding: const EdgeInsets.only(left: 0, right: 34.0), child: Text( widget.inactiveText, style: TextStyle( color: widget.inactiveTextColor, fontWeight: FontWeight.w900, fontSize: 16.0, ), ), ) : Container(), ], ), ), ), ); }, ); } }
说明
原页面的代码无需修改,仅修改自定义CustomSwitch的实现即可。修改后,当父组件通过setState更新_Location或OutAndAbout变量时,自定义Switch会通过didUpdateWidget感知到value的变化,自动调整内部动画状态,实现UI与变量值的同步。
内容的提问来源于stack exchange,提问作者Umer Yaseen
相关产品推荐
相关产品推荐

