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

Flutter卡片组件中项目选择、取消选择及跨卡片禁用功能实现求助

解决方案:跨卡片同步岗位选中与禁用状态

我明白你想要实现的是:当某张卡片里的IT/DEV/TEST/HR被选中时,它变成蓝色,同时其他所有卡片里的同名岗位要被禁用(不能点击且视觉上区分)。之前用Map没成功,是因为需要统一管理每个岗位的选中状态,而不是单张卡片的独立状态。

下面是修改后的完整代码,我会一步步解释关键变化:

关键逻辑说明

  1. 全局状态管理:新增Map<String, int?> selectedPositions,键是岗位名称(IT/DEV/TEST/HR),值是选中该岗位的卡片索引(null表示没有卡片选中这个岗位),用来统一追踪每个岗位的选中情况。
  2. 点击交互逻辑:点击岗位时做三种判断:
    • 如果该岗位未被任何卡片选中,就记录当前卡片索引为选中者
    • 如果该岗位已经被当前卡片选中,就取消选中(设为null)
    • 如果该岗位被其他卡片选中,不做任何操作(实现禁用效果)
  3. 视觉状态区分:
    • 当前卡片选中的岗位:显示蓝色
    • 被其他卡片选中的岗位:显示浅灰色(禁用状态)
    • 未被选中的岗位:显示正常灰色

完整修改代码

import 'package:flutter/material.dart';

void main() { runApp(App()); }

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: CardWithTextformfield(),
    );
  }
}

class CardWithTextformfield extends StatefulWidget {
  const CardWithTextformfield({Key? key}) : super(key: key);

  @override
  _CardWithTextformfieldState createState() => _CardWithTextformfieldState();
}

class _CardWithTextformfieldState extends State<CardWithTextformfield> with AutomaticKeepAliveClientMixin {
  @override
  bool get wantKeepAlive => true;

  var name = <TextEditingController>[];
  var id = <TextEditingController>[];
  var addCard = 1;
  // 新增:管理每个岗位的选中卡片索引,null表示未被选中
  Map<String, int?> selectedPositions = {
    'IT': null,
    'DEV': null,
    'TEST': null,
    'HR': null,
  };

  void incrementcard(){
    setState(() {
      if(addCard >=4){
        return;
      }
      addCard++;
    });
  }

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return Scaffold(
      appBar: AppBar(
        title: Text('Card with TextformField'),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: incrementcard,
        child: Icon(Icons.add),
      ),
      body: Container(
        child: ListView.builder(
          itemCount: addCard,
          itemBuilder: (context, index){
            return cardslist(index);
          }
        ),
      ),
    );
  }

  Widget cardslist(int index){
    if(name.length <= index){
      name.add(TextEditingController());
      id.add(TextEditingController());
    }

    // 封装岗位按钮的构建逻辑,避免重复代码
    Widget buildPositionButton(String position) {
      // 判断当前岗位的状态
      bool isSelectedByCurrentCard = selectedPositions[position] == index;
      bool isSelectedByOtherCard = selectedPositions[position] != null && selectedPositions[position] != index;

      return GestureDetector(
        // 只有当岗位未被选中,或者被当前卡片选中时,才响应点击
        onTap: isSelectedByOtherCard ? null : () {
          setState(() {
            if (isSelectedByCurrentCard) {
              // 当前卡片已选中,取消选中
              selectedPositions[position] = null;
            } else {
              // 选中当前卡片的这个岗位
              selectedPositions[position] = index;
            }
          });
        },
        child: Container(
          width: 50,height: 50,
          margin: EdgeInsets.all(10),
          decoration: BoxDecoration(
            shape: BoxShape.rectangle,
            color: isSelectedByCurrentCard 
                ? Colors.blue // 选中状态:蓝色
                : isSelectedByOtherCard 
                    ? Colors.grey[400] // 被其他卡片选中:禁用浅灰
                    : Colors.grey, // 未选中:正常灰色
          ),
          child: Center(child: Text(position),),
        ),
      );
    }

    return Card(
      margin: EdgeInsets.all(10),
      child: Container(
        child: Column(
          children: [
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Container(
                  margin: EdgeInsets.all(10),
                  child: Text('Team Name: ')),
                Expanded(child: TextFormField(
                  controller: name[index],
                  decoration: InputDecoration(hintText: 'Team Name'),
                ),),
                Container(
                  margin: EdgeInsets.all(10),
                  child: Text('Team Id: '),),
                Expanded(child: TextFormField(
                  controller: id[index],
                  decoration: InputDecoration(hintText: 'Team Id'),
                ),),
              ],
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                buildPositionButton('IT'),
                buildPositionButton('DEV'),
                buildPositionButton('TEST'),
                buildPositionButton('HR'),
              ],
            )
          ],
        ),
      ),
    );
  }
}

这样修改后,就能实现你要的效果:选中某卡片的岗位变蓝,其他卡片的同名岗位会变成浅灰色且无法点击,直到选中的岗位被取消为止。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 07:47:35