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

Flutter页面切换后按钮状态无法保留的修复方案咨询

Flutter按钮状态丢失问题修复方案

问题根源

  1. 状态同步失效:MyButton组件本地状态isPressed始终初始化为false,未与父组件传入的状态同步,导致页面切换后状态重置。
  2. 状态共享错误:所有按钮共用同一个全局布尔状态,无法区分多个按钮的独立按压状态。
  3. 状态冗余冲突:HomePage同时维护本地状态和接收父组件状态,造成状态不一致。

修复步骤

1. 全局状态改为多按钮独立状态(main.dart)

将单个布尔值改为存储每个按钮状态的列表,适配ListView中的3个按钮:

import 'package:ace_app/pages/form.dart';
import 'package:flutter/material.dart';
import 'package:ace_app/components/bar_bottom.dart';
import 'package:ace_app/pages/home.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  // 存储3个按钮的状态,初始均为false
  List<bool> buttonStates = List.filled(3, false);
  int _currentIndex = 0;

  // 更新指定索引的按钮状态
  void updateButtonState(int index, bool newState) {
    setState(() {
      buttonStates[index] = newState;
    });
  }

  setCurrentIndex(index) {
    setState(() {
      _currentIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
          body: [
            HomePage(
              buttonStates: buttonStates,
              updateButtonState: updateButtonState,
            ),
            const FormPage()
          ][_currentIndex],
          bottomNavigationBar: BottomNavigation(
            onIndexChanged: setCurrentIndex,
            currentIndex: _currentIndex,
          ),
        )
    );
  }
}

2. 重构HomePage,传递对应按钮的状态(home.dart)

移除本地冗余状态,直接使用全局状态列表,给每个按钮传递对应索引的状态:

import 'package:flutter/material.dart';
import 'package:ace_app/components/button.dart';

class HomePage extends StatefulWidget {
  final List<bool> buttonStates;
  final Function(int, bool) updateButtonState;

  const HomePage({
    Key? key,
    required this.buttonStates,
    required this.updateButtonState,
  }) : super(key: key);

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text(
          "ACE PRESENCE",
          style: TextStyle(
            fontFamily: "Poppins",
            fontSize: 20,
            color: Colors.white,
          ),
        ),
        toolbarHeight: 70,
        backgroundColor: Colors.blue,
        actions: [
          PopupMenuButton<String>(
            icon: const Icon(
              Icons.more_vert,
              color: Colors.white,
            ),
            onSelected: (String value) {
              if (value == 'reset') {
                // 重置所有按钮状态
                for (int i = 0; i < widget.buttonStates.length; i++) {
                  widget.updateButtonState(i, false);
                }
              }
            },
            itemBuilder: (BuildContext context) => <PopupMenuEntry<String>>[
              const PopupMenuItem<String>(
                value: 'reset',
                child: Text(
                  'Réinitialiser',
                  style: TextStyle(fontFamily: "Poppins", fontSize: 15.0),
                ),
              ),
            ],
          ),
        ],
      ),
      body: Column(
        children: [
          const SizedBox(height: 20.0),
          const Padding(
            padding: EdgeInsets.all(15.0),
            child: TextField(
              decoration: InputDecoration(
                prefixIcon: Icon(Icons.search),
                hintText: "Entrez votre nom",
                border: OutlineInputBorder(
                  borderRadius: BorderRadius.all(Radius.circular(25.0)),
                ),
                focusedBorder: OutlineInputBorder(
                  borderSide: BorderSide(color: Colors.blue),
                  borderRadius: BorderRadius.all(Radius.circular(25.0)),
                ),
                contentPadding: EdgeInsets.all(15.0),
              ),
            ),
          ),
          const SizedBox(height: 0.0),
          Expanded(
            child: ListView.builder(
              itemCount: widget.buttonStates.length,
              itemBuilder: (BuildContext context, int index) {
                return Card(
                  margin: const EdgeInsets.symmetric(vertical: 8.0),
                  color: Theme.of(context).scaffoldBackgroundColor,
                  child: ListTile(
                    contentPadding: const EdgeInsets.symmetric(
                      vertical: 8.0,
                      horizontal: 16.0,
                    ),
                    leading: const CircleAvatar(
                      backgroundColor: Colors.blue,
                      child: Icon(
                        Icons.person,
                        color: Colors.white,
                      ),
                    ),
                    title: const Center(child: Text("Nom et prénom")),
                    subtitle: const Center(child: Text("Numéro de téléphone - Classe")),
                    // 给每个按钮传递对应索引的状态和更新方法
                    trailing: MyButton(
                      isPressed: widget.buttonStates[index],
                      onPressed: () {
                        widget.updateButtonState(index, !widget.buttonStates[index]);
                      },
                    ),
                  ),
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}

3. 简化MyButton,依赖父组件状态(button.dart)

移除本地状态,直接使用父组件传入的状态,确保状态完全同步:

import 'package:flutter/material.dart';

class MyButton extends StatelessWidget {
  final bool isPressed;
  final VoidCallback onPressed;

  const MyButton({
    Key? key,
    required this.isPressed,
    required this.onPressed,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      style: ButtonStyle(
        backgroundColor: MaterialStateProperty.all(isPressed ? Colors.grey : Colors.blue),
        shape: MaterialStateProperty.all<RoundedRectangleBorder>(
          RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(8.0),
          ),
        ),
        padding: MaterialStateProperty.all(
          const EdgeInsets.all(10.0),
        ),
      ),
      // 根据父组件状态决定是否可点击
      onPressed: isPressed ? null : onPressed,
      child: const Text(
        "Confirmer",
        style: TextStyle(color: Colors.white),
      ),
    );
  }
}

修复说明

  • 全局状态用List<bool>存储每个按钮的独立状态,解决多按钮状态冲突问题。
  • MyButton改为无状态组件,完全依赖父组件传入的状态,避免本地状态与全局状态不同步。
  • 页面切换时,全局状态由MyApp维护,不会因页面重建丢失,返回HomePage时按钮状态自动恢复。

内容的提问来源于stack exchange,提问作者Isaac N'cho

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 11:19:52