Flutter中setState修改静态变量后AppBar未更新问题求助
类WhatsApp应用多选模式下AppBar不更新问题
我正在开发一款类WhatsApp应用,长按联系人的多选功能已实现,但希望此时首页(HomeScreen)的AppBar动作组件能随之切换。我在ChatPage中通过setState修改HomeScreen的静态变量selected,但执行长按操作后,AppBar并未按预期更新。
ChatPage 相关代码
import 'dart:math'; import 'package:contacts_service/contacts_service.dart'; import 'package:flutter/material.dart'; import 'package:flutter/src/gestures/long_press.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:whatsapp/Model/ChatModel.dart'; import 'package:whatsapp/Screens/chat/chatScreen.dart'; import 'package:whatsapp/constants/colors.dart'; import '../CustomUI/show_image_fullScreen.dart'; import '../Screens/contacts/select_contact.dart'; import '../Screens/home/HomeScreen.dart'; import '../utils/theme_manager.dart'; class ChatPage extends StatefulWidget { const ChatPage({Key? key, required this.chatModels}) : super(key: key); final List<ChatModel> chatModels; @override State<ChatPage> createState() => _ChatPageState(); } class _ChatPageState extends State<ChatPage> { List<Contact>? contacts; List<int> selectedIndexList = []; LongPressDownDetails? detailPress; @override void initState() { super.initState(); getAllContacts(); } void getAllContacts() async { bool isGranted = await Permission.contacts.isGranted; if (!isGranted) { isGranted = await Permission.contacts.request().isGranted; } List myContacts = (await ContactsService.getContacts()).toList(); setState(() { contacts = myContacts.cast<Contact>(); }); } @override Widget build(BuildContext context) { return Scaffold( floatingActionButton: FloatingActionButton( onPressed: () { Navigator.pushNamed(context, SelectContact.routName); }, child: Icon(Icons.chat, color: Colors.white), ), body: contacts == null ? const Center( child: CircularProgressIndicator(), ) : ListView.builder( itemCount: contacts!.length, itemBuilder: (BuildContext context, index) { int randomNumber = Random().nextInt(colors.length); return Column( children: [ const SizedBox( height: 30, ), GestureDetector( onLongPress: () { if (!HomeScreen.selected){ setState(() { HomeScreen.selected = true; selectedIndexList.add(index); }); } else { if (selectedIndexList.contains(index)){ setState(() { selectedIndexList.remove(index); }); } else { setState(() { selectedIndexList.add(index); }); } } if (selectedIndexList.isEmpty){ setState(() { HomeScreen.selected = false; }); } }, child: ListTile( leading: InkWell( onTap: () { Navigator.push(context, MaterialPageRoute(builder: (context) { return ShowImageFullScreen( sorceChat: widget.chatModels[0], image: Image.asset("assets/1.jpg"), tabBarOptions: false, ); })); }, child: (contacts![index].avatar == null) ? CircleAvatar( backgroundColor: Colors.grey, radius: 30, child: SvgPicture.asset( "assets/person.svg", color: Colors.grey, width: 38, height: 38, ), ) : Stack( children: [ CircleAvatar( backgroundColor: colors[randomNumber] ['color'], radius: 30, child: Text( contacts![index].initials(), style: TextStyle( color: colors[randomNumber] ['mode'] == 'light' ? Colors.black54 : Colors.white), ), ), HomeScreen.selected && selectedIndexList .contains(index) ? Positioned( bottom: 0, right: 0, child: CircleAvatar( backgroundColor: ThemeManeger() .checkIsDark( context) ? tabColor : Colors.teal, radius: 11, child: Container( decoration: BoxDecoration( border: Border.all( color: ThemeManeger() .checkIsDark( context) ? Colors.white : Colors.black, width: 2), borderRadius: BorderRadius .circular(11)), child: Icon( Icons.check, color: ThemeManeger() .checkIsDark( context) ? Colors.white : Colors.black, size: 18, ), ), ), ) : const Positioned( child: SizedBox()) ], )), onTap: () { if (!HomeScreen.selected){ Navigator.push( context, MaterialPageRoute( builder: (context) => ChatScreen( chatModel: widget.chatModels[index], ), ), ); } else { if (selectedIndexList.contains(index)){ setState(() { selectedIndexList.remove(index); }); } else { setState(() { selectedIndexList.add(index); }); } } if (selectedIndexList.isEmpty){ setState(() { HomeScreen.selected = false; }); } }, title: Text( contacts![index].displayName!, style: TextStyle( color: ThemeManeger().checkIsDark(context) ? Colors.white : Colors.black), ), subtitle: Row( children: [ Icon( Icons.done_all, color: ThemeManeger().checkIsDark(context) ? Colors.white70 : Colors.black45, ), Text( "سلام", style: TextStyle( color: ThemeManeger().checkIsDark(context) ? Colors.white70 : Colors.black45), ), ], ), trailing: Text( "3:00", style: TextStyle( color: ThemeManeger().checkIsDark(context) ? Colors.white70 : Colors.black45, fontSize: 12), ), ), ) ], ); })); } }
HomeScreen 相关代码
import 'package:flutter/material.dart'; import 'package:flutter_feather_icons/flutter_feather_icons.dart'; import 'package:theme_provider/theme_provider.dart'; import 'package:whatsapp/Model/ChatModel.dart'; import 'package:whatsapp/constants/colors.dart'; import 'package:whatsapp/pages/ChatPage.dart'; import 'package:whatsapp/pages/StatusPage.dart'; import '../../groups/group.dart'; import '../../pages/CallsPage.dart'; import '../../pages/CommunityPage.dart'; import '../../utils/theme_manager.dart'; class HomeScreen extends StatefulWidget { static const String routName = "/Home-screen"; static bool selected = false; const HomeScreen({Key? key, required this.chatModels}) : super(key: key); final List<ChatModel> chatModels; static int index = 1; @override State<HomeScreen> createState() => _HomeScreenState(); } class _HomeScreenState extends State<HomeScreen> with SingleTickerProviderStateMixin { TabController? controller; @override void initState() { super.initState(); controller = TabController(length: 4, vsync: this, initialIndex: 1); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text( "Whatsapp", style: TextStyle( color: ThemeManeger().checkIsDark(context) ? Colors.grey : Colors.white), ), actions: [ HomeScreen.selected == false ? Row( children: [ IconButton( onPressed: () { showDialog( context: context, builder: (_) => ThemeConsumer(child: ThemeDialog())); }, icon: Icon( Icons.palette, color: ThemeManeger().checkIsDark(context) ? Colors.grey : Colors.white60, ), ), IconButton( onPressed: () {}, icon: Icon(FeatherIcons.camera, color: ThemeManeger().checkIsDark(context) ? Colors.grey : Colors.white70)), IconButton( icon: Icon( Icons.search, color: ThemeManeger().checkIsDark(context) ? Colors.grey : Colors.white70, ), onPressed: () {}, ), PopupMenuButton( color: ThemeManeger().checkIsDark(context) ? appBarColor : Colors.white, icon: Icon(Icons.more_vert, color: ThemeManeger().checkIsDark(context) ? Colors.grey : Colors.white), onSelected: (value) { if (value == 0) { Navigator.pushNamed(context, CreateGroup.routName); } }, itemBuilder: (BuildContext context) { return [ PopupMenuItem( value: 0, child: Text( "New group", style: TextStyle( color: ThemeManeger().checkIsDark(context) ? Colors.white : Colors.black), ), ), PopupMenuItem( child: Text( "New broadcast", style: TextStyle( color: ThemeManeger().checkIsDark(context) ? Colors.white : Colors.black), ), ), PopupMenuItem( child: Text( "Linked devices", style: TextStyle( color: ThemeManeger().checkIsDark(context) ? Colors.white : Colors.black), ), ), PopupMenuItem( child: Text( "Starred messages", style: TextStyle( color: ThemeManeger().checkIsDark(context) ? Colors.white : Colors.black), ), ), PopupMenuItem( child: Text( "Settings", style: TextStyle( color: ThemeManeger().checkIsDark(context) ? Colors.white : Colors.black), ), ), ]; }) ], ) : Row() ], bottom: TabBar( unselectedLabelColor: ThemeManeger().checkIsDark(context) ? Colors.grey : Colors.white70, labelColor: ThemeManeger().checkIsDark(context) ? tabColor : Colors.white, indicatorColor: ThemeManeger().checkIsDark(context) ? tabColor : Colors.white, controller: controller, tabs: const [ Tab( icon: Icon(Icons.people), ), Tab( text: "Chats", ), Tab( text: "Status", ), Tab( text: "Calls", ), ], ), ), body: TabBarView( controller: controller, children: [ const CommunityPage(), ChatPage( chatModels: widget.chatModels, ), const StatusPage(), const CallsPage(), ], ), ); } }
问题原因
直接修改HomeScreen的静态变量selected不会触发HomeScreen的setState()调用,因此AppBar不会重新构建更新UI。静态变量的变化无法通知State组件刷新视图。
解决方案
方法一:使用回调函数传递状态
通过在ChatPage中添加回调参数,将多选状态变化通知给HomeScreen,触发HomeScreen的状态更新:
- 修改ChatPage的StatefulWidget,添加回调参数:
class ChatPage extends StatefulWidget { const ChatPage({ Key? key, required this.chatModels, required this.onSelectionChange, }) : super(key: key); final List<ChatModel> chatModels; final Function(bool isSelected) onSelectionChange; @override State<ChatPage> createState() => _ChatPageState(); }
- 在ChatPage的长按和点击事件中调用回调:
// 长按事件 onLongPress: () { if (!widget.selectionNotifier.value){ setState(() { selectedIndexList.add(index); }); widget.onSelectionChange(true); } else { setState(() { selectedIndexList.contains(index) ? selectedIndexList.remove(index) : selectedIndexList.add(index); }); if (selectedIndexList.isEmpty){ widget.onSelectionChange(false); } } }, // 点击事件 onTap: () { if (!widget.selectionNotifier.value){ Navigator.push( context, MaterialPageRoute( builder: (context) => ChatScreen( chatModel: widget.chatModels[index], ), ), ); } else { setState(() { selectedIndexList.contains(index) ? selectedIndexList.remove(index) : selectedIndexList.add(index); }); if (selectedIndexList.isEmpty){ widget.onSelectionChange(false); } } },
- 修改HomeScreen,移除静态变量
selected改为本地状态,并传入回调:
class _HomeScreenState extends State<HomeScreen> with SingleTickerProviderStateMixin { TabController? controller; bool _isSelected = false; @override void initState() { super.initState(); controller = TabController(length: 4, vsync: this, initialIndex: 1); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text( "Whatsapp", style: TextStyle( color: ThemeManeger().checkIsDark(context) ? Colors.grey : Colors.white), ), actions: [ !_isSelected ? Row(/* 原有动作组件 */) : Row() ], // 其他AppBar配置 ), body: TabBarView( controller: controller, children: [ const CommunityPage(), ChatPage( chatModels: widget.chatModels, onSelectionChange: (bool isSelected) { setState(() { _isSelected = isSelected; }); }, ), const StatusPage(), const CallsPage(), ], ), ); } }
方法二:使用ValueNotifier进行状态管理
如果需要多个组件共享多选状态,推荐使用ValueNotifier:
- 在HomeScreen中创建ValueNotifier:
class _HomeScreenState extends State<HomeScreen> with SingleTickerProviderStateMixin { TabController? controller; final ValueNotifier<bool> _selectionNotifier = ValueNotifier(false); @override void dispose() { _selectionNotifier.dispose(); super.dispose(); } // 其他代码 }
- 使用ValueListenableBuilder监听状态变化更新AppBar:
appBar: AppBar( title: Text("Whatsapp"), actions: [ ValueListenableBuilder<bool>( valueListenable: _selectionNotifier, builder: (context, isSelected, child) { return !isSelected ? Row(/* 原有动作组件 */) : Row(); }, ), ], // 其他AppBar配置 ),
- 传递ValueNotifier给ChatPage:
ChatPage( chatModels: widget.chatModels, selectionNotifier: _selectionNotifier, ),
- 修改ChatPage接收并更新ValueNotifier:
class ChatPage extends StatefulWidget { const ChatPage({ Key? key, required this.chatModels, required this.selectionNotifier, }) : super(key: key); final List<ChatModel> chatModels; final ValueNotifier<bool> selectionNotifier; @override State<ChatPage> createState() => _ChatPageState(); } class _ChatPage
相关产品推荐
相关产品推荐

