Flutter选中5个或全部复选框时按钮变色并跳转首页实现
条款同意页逻辑修复方案
核心问题说明
你现有代码存在3个直接导致逻辑不符合要求的问题:
- 按钮激活判断仅校验了「6项全选」的场景,没有覆盖「前5项必填条款全部选中、第6项选填项任意状态」的合法场景
- 按钮点击跳转的判断条件仅绑定全选框状态,前5项选完但没选第6项时即使按钮变蓝也无法跳转
- 存在冗余的控制器实例生成逻辑,容易出现状态不同步的问题
具体修改逻辑
- 提取统一的合法状态判断规则:只要前5项必填条款全部选中,不管第6项选填项是否选中,按钮都置为蓝色可点击跳转
- 修正全选框联动规则:所有6项全选时自动勾选全选框,任意一项取消则全选框取消勾选;点击全选框时同步切换所有6个条款的选中状态
- 清理重复初始化的CheckBoxState实例,避免状态错乱
修正后完整代码
class TermsAgreementPage extends StatelessWidget { TermsAgreementPage({Key? key}) : super(key: key); // 全选状态实例 final alltermsAndConditions = CheckBoxState('전체동의'); // 条款列表 final List<CheckBoxState> termsAndConditions = [ CheckBoxState('이용 약관 동의(필수)', '니어엑스 서비스 이용 통합 약관입니다.'), CheckBoxState('개인정보 처리방침 동의(필수)', '개인정보보호 포털 법률에 의거한 제공동의로 필수 사항입니다.'), CheckBoxState('개인정보 제3자 제공동의(필수)', '개인정보보호 포털 법률에 의거한 제공 동의로 필수 사항입니다.'), CheckBoxState('위치기반 서비스 이용약관(필수)', '주변 가게들 검색에 사용됩니다.'), CheckBoxState('전자금융거래 이용약관(필수)', '구매 또는 결제 사항이 있을 경우 제공 동의로 필수 사항입니다.'), CheckBoxState('니어엑스 혜택 알림 동의(선택)','미선택 시 주변가게 할인 및 만기 다가오는 쿠폰 알림 사용 불가.') ]; // 统一跳转权限判断:前5项必填全部选中即满足条件 bool get canNavigate { for(int i = 0; i < 5; i++){ if(!termsAndConditions[i].isChecked.value) return false; } return true; } @override Widget build(BuildContext context) { Size size = MediaQuery.of(context).size; return Scaffold( body: Padding( padding: const EdgeInsets.only(top: 80.0, bottom: 40), child: Column( children: [ Expanded( flex: 1, child: SizedBox( width: size.width, child: Column( children: const [ Text( '이용 약관 동의', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, ), ), Text( '아래의 약관에 동의 하신 후 서비스를 이용해 주시기 바랍니다.', style: TextStyle( fontSize: 10, fontWeight: FontWeight.bold, color: Colors.grey), ), ], ), ), ), Expanded( flex: 6, child: Obx( () => ListView( children: [ buildGroupCheckbox(), Divider(color: Colors.grey[300], height: 5, thickness: 3), ...termsAndConditions.map(buildCheckbox).toList(), ElevatedButton( style: ElevatedButton.styleFrom( primary: canNavigate ? Colors.blue : Colors.grey[400], padding: const EdgeInsets.symmetric( horizontal: 150, vertical: 10), textStyle: const TextStyle( fontSize: 15, fontWeight: FontWeight.w400, color: Colors.white)), onPressed: () { if(canNavigate) { Get.toNamed('/home'); } }, child: const Text('시작하기'), ), ], ), ), ), ], ), ), ); } Widget buildGroupCheckbox() { return CheckboxListTile( controlAffinity: ListTileControlAffinity.leading, secondary: TextButton( onPressed: () { // 原代码此处直接写跳转首页属于逻辑错误,替换为查看条款全文的对应逻辑即可 }, child: const Text( '전문보기', style: TextStyle(fontSize: 10.0, color: Colors.blue), )), title: Text( alltermsAndConditions.title, style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w500), ), onChanged: toggleAllCheckBox, value: termsAndConditions.every((item) => item.isChecked.value), ); } void toggleAllCheckBox(bool? value) { if (value == null) return; for (var item in termsAndConditions) { item.isChecked.value = value; } } Widget buildCheckbox(CheckBoxState checkBoxState) { return CheckboxListTile( controlAffinity: ListTileControlAffinity.leading, title: Text( checkBoxState.title, style: const TextStyle(fontSize: 12), ), subtitle: Text( checkBoxState.subTitle, style: const TextStyle(fontSize: 9, color: Colors.grey), ), onChanged: (value) { checkBoxState.isChecked.value = value!; }, value: checkBoxState.isChecked.value ); } } class CheckBoxState extends GetxController { RxBool isChecked = false.obs; String title; String subTitle; CheckBoxState(this.title,[this.subTitle = '']); }
效果验证
- 仅选中前5项必填条款:按钮变蓝,点击可正常跳转首页
- 6项全部选中:按钮变蓝,点击可正常跳转首页
- 前5项任意一项未选中:按钮保持灰色,点击无响应
- 点击全选框:同步选中/取消所有条款,全选框状态和所有条款的选中状态实时同步
内容的提问来源于stack exchange,提问作者rorososo10000
相关产品推荐
相关产品推荐

