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

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的状态更新:

  1. 修改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();
}
  1. 在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);
    }
  }
},
  1. 修改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:

  1. 在HomeScreen中创建ValueNotifier:
class _HomeScreenState extends State<HomeScreen>
    with SingleTickerProviderStateMixin {
  TabController? controller;
  final ValueNotifier<bool> _selectionNotifier = ValueNotifier(false);

  @override
  void dispose() {
    _selectionNotifier.dispose();
    super.dispose();
  }

  // 其他代码
}
  1. 使用ValueListenableBuilder监听状态变化更新AppBar:
appBar: AppBar(
  title: Text("Whatsapp"),
  actions: [
    ValueListenableBuilder<bool>(
      valueListenable: _selectionNotifier,
      builder: (context, isSelected, child) {
        return !isSelected
            ? Row(/* 原有动作组件 */)
            : Row();
      },
    ),
  ],
  // 其他AppBar配置
),
  1. 传递ValueNotifier给ChatPage:
ChatPage(
  chatModels: widget.chatModels,
  selectionNotifier: _selectionNotifier,
),
  1. 修改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
相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 15:02:34