Flutter中如何让每个用户卡片的DropdownButton选中项独立?
问题解决:用户角色选择器同步变化的修复
核心问题是所有用户卡片共用了同一个全局角色变量,加上下拉菜单的状态没有和单个用户绑定,导致选一个角色所有菜单跟着变。下面是具体的修复方案和修改后的代码:
问题根源
- 全局变量
String role = '1'被所有用户共享,修改时会触发所有依赖该变量的组件刷新 RoleMenu的初始选中值为空,没有和用户当前的角色关联,且回调会修改全局变量,导致所有菜单同步更新- 每个用户的待修改角色没有独立存储,共用状态导致互相干扰
修复方案
- 移除全局
role变量,改为为每个用户维护独立的待修改角色状态 - 重构
RoleMenu,让它接收用户当前角色作为初始值,选中后直接回传结果给父组件 - 在用户卡片的构建逻辑中,为每个用户保存独立的待修改角色,避免交叉影响
修改后的完整代码
import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; final user = FirebaseAuth.instance.currentUser!; Stream<QuerySnapshot> readUsers() => FirebaseFirestore.instance.collection('users').snapshots(); Future accDialog(BuildContext context) => showDialog( context: context, builder: (context) => StatefulBuilder( builder: (BuildContext context, setState) => Dialog( child: Container( margin: const EdgeInsets.all(24), child: StreamBuilder( stream: readUsers(), builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) { // 为每个用户存储独立的待修改角色,用文档ID作为key final Map<String, String> pendingRoles = {}; if (snapshot.hasError) { return const Text('Algo ha salido mal!'); } if (snapshot.connectionState == ConnectionState.waiting) { return const Text("Cargando"); } return ListView( shrinkWrap: true, children: snapshot.data!.docs .map((DocumentSnapshot document) { Map<String, dynamic> data = document.data()! as Map<String, dynamic>; // 初始化当前用户的待修改角色为其现有角色 pendingRoles.putIfAbsent(document.id, () => data['role']); return Card( margin: const EdgeInsets.all(8), child: Padding( padding: const EdgeInsets.all(8), child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ Text( data['name'], style: Theme.of(context).textTheme.titleMedium, ), Text('Correo: ${data['email']}'), Text('Rol Actual: ${data['role']}'), Row( children: [ Padding( padding: const EdgeInsets.all(8.0), child: RoleMenu( initialValue: data['role'], onRoleChanged: (newRole) { setState(() { // 更新当前用户的待修改角色 pendingRoles[document.id] = newRole; }); }, )), const Spacer(), ElevatedButton( onPressed: () { final targetRole = pendingRoles[document.id]; if (targetRole == null) return; // 使用当前用户的待修改角色更新数据库 final setRole = <String, String>{ "role": targetRole, }; FirebaseFirestore.instance .collection('users') .doc(document.id) .set(setRole, SetOptions(merge: true)); }, child: const Text('Guardar')) ], ) ], ), ), ); }) .toList() .cast(), ); }, ), ), ), ), ); class RoleMenu extends StatefulWidget { // 接收用户当前的角色作为初始选中值 final String initialValue; // 回调函数,回传选中的角色给父组件 final Function(String) onRoleChanged; const RoleMenu({super.key, required this.initialValue, required this.onRoleChanged}); @override State<RoleMenu> createState() => _RoleMenuState(); } class _RoleMenuState extends State<RoleMenu> { late String selected; @override void initState() { super.initState(); // 初始化选中值为用户当前的角色 selected = widget.initialValue; } // 当父组件的initialValue变化时更新选中值(比如用户角色被成功修改后) @override void didUpdateWidget(covariant RoleMenu oldWidget) { super.didUpdateWidget(oldWidget); if (oldWidget.initialValue != widget.initialValue) { setState(() { selected = widget.initialValue; }); } } @override Widget build(BuildContext context) { return DropdownButtonHideUnderline( child: DropdownButton<String>( enableFeedback: true, dropdownColor: ElevationOverlay.applySurfaceTint( Theme.of(context).colorScheme.surface, Theme.of(context).colorScheme.surfaceTint, 2), iconEnabledColor: Theme.of(context).colorScheme.onSurfaceVariant, style: Theme.of(context).textTheme.labelLarge, items: const [ DropdownMenuItem<String>( value: 'User', child: Text('Usuario'), ), DropdownMenuItem<String>( value: 'Admin', child: Text('Admin'), ), ], value: selected, onChanged: (value) { if (value == null) return; setState(() { selected = value; }); // 通知父组件选中的角色 widget.onRoleChanged(value); }, ), ); } }
关键修改说明
- 新增
pendingRolesMap,用用户文档ID作为key,存储每个用户独立的待修改角色,避免全局变量的干扰 RoleMenu新增initialValue参数,初始化时显示用户当前的角色,更符合交互逻辑- 移除全局
role变量,改用局部的pendingRoles管理每个用户的待修改状态 - 给
RoleMenu添加didUpdateWidget方法,确保当用户角色在数据库中被修改后,下拉菜单能同步更新显示最新值
内容的提问来源于stack exchange,提问作者Willders Carvajal
相关产品推荐
相关产品推荐

