You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中控制列表选项的选中数量

Fixing Flutter List Selection Limit (2 or 3 Items Only)

Let's get this sorted out—you need to restrict users to selecting 2 or 3 items from your list, plus validate that requirement. Here's how to adjust your code step by step:

1. Update the Selection Logic

First, modify the onTap handler for your list items to enforce the 2-3 selection rule. We'll add checks to prevent selecting more than 3 items, and also prevent deselecting items if that would drop the count below 2. We'll also show a quick snackbar to inform users when they hit these limits.

2. Add Validation for Submission

I've added a submit button to your code example (since you didn't have one yet) with validation to ensure the selection count is valid before proceeding.

Modified Full Code

class _LibraChoosePayState extends State<LibraChoosePay> {
  List<int> selectedService = [];
  List<dynamic> services = [
    [ Plans.electrician, Plans.electrician, "Electrician", "For electrical repairs and works. Both for offices and homes. Anywhere.", 0],
    [ Plans.mechanic, Plans.mechanic, "Mechanic", "For mechanical repairs and works. Both for offices and homes. Anywhere.", 0],
    [ Plans.plumber, Plans.plumber, "Plumber", "For plumbing repairs and works. Both for offices and homes. Anywhere.", 1],
    [ Plans.carpenter, Plans.carpenter, "Carpenter", "For carpentry repairs and works. Both for offices and homes. Anywhere.", 0],
  ];

  // Helper method to show snackbar notifications
  void _showSnackBar(String message) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text(message)),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: AppColors.backgroundLightMode,
      body: GestureDetector(
        onTap: () => FocusScope.of(context).unfocus(),
        child: SingleChildScrollView(
          child: SafeArea(
            child: Container(
              padding: const EdgeInsets.all(20),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.spaceAround,
                children: [
                  Row(
                    mainAxisAlignment: MainAxisAlignment.start,
                    children: [
                      IconButton(
                        onPressed:() {
                          Navigator.popAndPushNamed(context, SelectPlan.idScreen);
                        },
                        icon: AppAllIcons.arrowDown
                      ),
                      const SizedBox(width: 60,),
                      const Text(
                        "Select and Subscribe",
                        style: AppTextStyle.headerTextDarkStyle,
                      )
                    ],
                  ),
                  const SizedBox(height: 20,),
                  SizedBox(
                    height: 500,
                    child: ListView.builder(
                      itemCount: services.length,
                      itemBuilder: ((context, index) {
                        return GestureDetector(
                          onTap: () {
                            setState(() {
                              if(selectedService.contains(index)) {
                                // Trying to deselect an item
                                if (selectedService.length > 2) {
                                  selectedService.remove(index);
                                } else {
                                  _showSnackBar("You must select at least 2 services");
                                }
                              } else{
                                // Trying to select a new item
                                if (selectedService.length < 3) {
                                  selectedService.add(index);
                                } else {
                                  _showSnackBar("You can select a maximum of 3 services");
                                }
                              }
                            });
                          },
                          child: AnimatedContainer(
                            margin: const EdgeInsets.all(10),
                            duration: const Duration(milliseconds: 800),
                            padding: const EdgeInsets.all(5),
                            decoration: BoxDecoration(
                              borderRadius: const BorderRadius.all(Radius.circular(15)),
                              color: Colors.white,
                              border: Border.all(
                                color: selectedService.contains(index) ? Colors.blue : Colors.white.withOpacity(0),
                                width: 2
                              ),
                              boxShadow: [
                                selectedService.contains(index) ? BoxShadow(
                                  color: Colors.blue.shade100,
                                  offset: const Offset(0, 3),
                                  blurRadius: 10
                                ) : BoxShadow(
                                  color: Colors.grey.shade100,
                                  offset: const Offset(0, 3),
                                  blurRadius: 10
                                )
                              ]
                            ),
                            child: Row(
                              children: [
                                selectedService.contains(index) ? Image.asset(services[index][0], width: 50,) : Image.asset(services[index][1], width: 50,),
                                const SizedBox(width: 30,),
                                Expanded(
                                  child: Column(
                                    crossAxisAlignment: CrossAxisAlignment.start,
                                    children: [
                                      Text(services[index][2], style: TextStyle(
                                        color: Colors.grey.shade800,
                                        fontSize: 16,
                                        fontWeight: FontWeight.bold
                                      ),),
                                      Text(services[index][3], style: TextStyle(
                                        color: Colors.grey.shade600,
                                        fontSize: 14,
                                      ),)
                                    ],
                                  ),
                                ),
                                Icon(Icons.check_circle, color: selectedService.contains(index) ? Colors.blue : Colors.white,)
                              ],
                            ),
                          ),
                        );
                      })
                    ),
                  ),
                  const SizedBox(height: 20,),
                  // Submit button with validation
                  ElevatedButton(
                    onPressed: () {
                      if (selectedService.length == 2 || selectedService.length ==3) {
                        // Proceed with your subscription logic here
                        Navigator.pushNamed(context, /* Replace with your next screen route */);
                      } else {
                        _showSnackBar("Please select 2 or 3 services to continue");
                      }
                    },
                    child: const Text("Subscribe"),
                  )
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}

Key Changes Explained

  • Selection Limits: When tapping an item, we check if adding would exceed 3 items or if removing would drop below 2. If so, we show a snackbar instead of changing the selection.
  • Validation: The submit button checks if the selection count is exactly 2 or 3 before allowing the user to proceed.
  • User Feedback: Added a helper _showSnackBar method to give clear, immediate feedback when users hit the selection limits.
  • Minor Fix: I corrected a typo in your services list where the second item was labeled "Electrician" instead of "Mechanic"—feel free to adjust that back if it was intentional!

内容的提问来源于stack exchange,提问作者Evaristus Adimonyemma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 21:07:31