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

Flutter问题:默认选中的FilterChip无法正常切换状态

FilterChip默认选中后点击无响应的问题排查与解决

问题描述

实现分类列表的FilterChip时,部分Chip已按预期默认选中,但点击进行勾选/取消操作时毫无反应,始终保持初始选中状态。

问题代码

class Filters extends StatefulWidget {
    final List selected;
    Filters({Key? key, required this.selected}) : super(key: key);

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


class _FiltersState extends State<Filters> {

    Future<Map> getData() async {
        Tmdb instance = Tmdb();
        var data = await instance.getGenres();

        // Check for error.
        if (instance.error.isNotEmpty) {
            data = {'error': instance.error['message'], 'statusCode': instance.error['statusCode']};
        }

        return data;
    }

    @override
    Widget build(BuildContext context) {

   ...

                              child = Column(
                                  children: <Widget>[
                                      Padding(
                                          padding: const EdgeInsets.only(left:8.0),
                                          child: Align(
                                              alignment: Alignment.centerLeft,
                                              child: Container(
                                                  child: Wrap(
                                                      spacing: 5.0,
                                                      runSpacing: 3.0,
                                                      children: <Widget>[
                                                          for (var i = 0; i < data['genres'].length; i++) ...[
                                                              filterChipWidget(
                                                                  chipName: data['genres'][i]['name'],
                                                                  chipId: data['genres'][i]['id'],
                                                                  isChecked: widget.selected.contains(data['genres'][i]['id']),
                                                                  // Listen for the onSelected callback.
                                                                  onSelected:  (isChecked, genreId) {
                                                                      // Store the selected genre id
                                                                      if (isChecked) {
                                                                          if (!selectedItems.contains(genreId)) {
                                                                              selectedItems.add(genreId);
                                                                          }
                                                                      }
                                                                      // Remove the selected genre id
                                                                      else {
                                                                          if (selectedItems.contains(genreId)) {
                                                                              selectedItems.remove(genreId);
                                                                          }
                                                                      }
                                                                  }
                                                              ),
                                                          ]
                                                      ],
                                                  )
                                              ),
                                          ),
                                      ),

   ...


   }
}

class filterChipWidget extends StatefulWidget {
    final String chipName;
    final int chipId;
    final bool isChecked;
    Function(bool, int) onSelected;

    filterChipWidget({Key? key, required this.chipName, required this.chipId, required this.isChecked, required this.onSelected}) : super(key: key);

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

class _filterChipWidgetState extends State<filterChipWidget> {
    var _isSelected = false;

    @override
    Widget build(BuildContext context) {
        _isSelected = widget.isChecked ? true : false;
        return FilterChip(
            label: Text(widget.chipName),
            labelStyle: TextStyle(color: Color(0xff6200ee),fontSize: 16.0,fontWeight: FontWeight.bold),
            selected: _isSelected,
            shape:RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(
                  30.0),),
            backgroundColor: Color(0xffededed),
            onSelected: (isSelected) {
                setState(() {
                    _isSelected = isSelected;
                    widget.onSelected(isSelected, widget.chipId);
                }); 
            },  
            selectedColor: Color(0xffeadffd),
        );  
    }
}

问题根源

  1. 子组件状态被强制重置:_filterChipWidgetState的build方法中,每次UI重建都会把_isSelected赋值为widget.isChecked,而widget.isChecked依赖父组件初始传入的固定列表widget.selected,导致点击修改的状态被直接覆盖。
  2. 父组件状态未同步更新:父组件维护的selectedItems修改后没有调用setState(),无法触发UI重建,子组件的isChecked始终基于初始值,不会随用户操作变化。
  3. 父组件状态初始化缺失:selectedItems没有从传入的widget.selected初始化,导致初始选中状态和后续操作的状态源不一致。

解决方案

1. 修正父组件状态管理

  • 初始化selectedItems为传入列表的副本,避免直接引用外部不可变列表。
  • 修改onSelected回调后调用setState(),触发UI重建。
  • 子组件的isChecked改为基于父组件实时的selectedItems判断。

2. 修正子组件状态逻辑

  • 不在build方法中重置_isSelected,而是在initState初始化初始状态,在didUpdateWidget中处理父组件传值变化的情况。

修改后的代码

父组件修改

class Filters extends StatefulWidget {
    final List selected;
    Filters({Key? key, required this.selected}) : super(key: key);

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


class _FiltersState extends State<Filters> {
    late List selectedItems;

    Future<Map> getData() async {
        Tmdb instance = Tmdb();
        var data = await instance.getGenres();

        if (instance.error.isNotEmpty) {
            data = {'error': instance.error['message'], 'statusCode': instance.error['statusCode']};
        }

        return data;
    }

    @override
    void initState() {
        super.initState();
        // 初始化选中状态为传入列表的副本
        selectedItems = List.from(widget.selected);
    }

    @override
    Widget build(BuildContext context) {
        // ... 其他代码

        child = Column(
            children: <Widget>[
                Padding(
                    padding: const EdgeInsets.only(left:8.0),
                    child: Align(
                        alignment: Alignment.centerLeft,
                        child: Container(
                            child: Wrap(
                                spacing: 5.0,
                                runSpacing: 3.0,
                                children: <Widget>[
                                    for (var i = 0; i < data['genres'].length; i++) ...[
                                        filterChipWidget(
                                            chipName: data['genres'][i]['name'],
                                            chipId: data['genres'][i]['id'],
                                            // 基于当前选中状态判断
                                            isChecked: selectedItems.contains(data['genres'][i]['id']),
                                            onSelected:  (isChecked, genreId) {
                                                setState(() {
                                                    if (isChecked) {
                                                        if (!selectedItems.contains(genreId)) {
                                                            selectedItems.add(genreId);
                                                        }
                                                    } else {
                                                        selectedItems.remove(genreId);
                                                    }
                                                });
                                            }
                                        ),
                                    ]
                                ],
                            )
                        ),
                    ),
                ),
            ],
        );

        // ... 其他代码
    }
}

子组件修改

class filterChipWidget extends StatefulWidget {
    final String chipName;
    final int chipId;
    final bool isChecked;
    final Function(bool, int) onSelected;

    filterChipWidget({Key? key, required this.chipName, required this.chipId, required this.isChecked, required this.onSelected}) : super(key: key);

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

class _filterChipWidgetState extends State<filterChipWidget> {
    late bool _isSelected;

    @override
    void initState() {
        super.initState();
        // 初始化选中状态
        _isSelected = widget.isChecked;
    }

    @override
    void didUpdateWidget(covariant filterChipWidget oldWidget) {
        super.didUpdateWidget(oldWidget);
        // 父组件传值变化时更新子组件状态
        if (oldWidget.isChecked != widget.isChecked) {
            setState(() {
                _isSelected = widget.isChecked;
            });
        }
    }

    @override
    Widget build(BuildContext context) {
        return FilterChip(
            label: Text(widget.chipName),
            labelStyle: const TextStyle(color: Color(0xff6200ee), fontSize: 16.0, fontWeight: FontWeight.bold),
            selected: _isSelected,
            shape: const RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(30.0),
            ),
            backgroundColor: const Color(0xffededed),
            onSelected: (isSelected) {
                setState(() {
                    _isSelected = isSelected;
                    widget.onSelected(isSelected, widget.chipId);
                }); 
            },  
            selectedColor: const Color(0xffeadffd),
        );  
    }
}

关键说明

  • 父组件通过setState()更新选中状态后,会触发子组件重新构建,此时子组件能获取到最新的选中状态。
  • 子组件仅在初始化和父组件传值变化时更新自身状态,避免了build方法中强制重置状态的问题,保证点击操作的状态能正常保留。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 07:24:57