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

Flutter主页面按钮状态未及时更新问题求助

问题

我有两个页面main.dart和second_page.dart,用Provider类(provider_class.dart)存储共享变量,Button_Data.dart定义按钮数据。当前问题:首次进入第二页完成操作后,点击「返回上一页」按钮回到主页面时,「Sell and Collect」按钮没有立即变为启用状态;必须第二次进入第二页再返回,该按钮才会启用。

需求:无论第二页是否访问过,从第二页返回主页面时,「Sell and Collect」按钮状态都能立即更新为启用状态。


main.dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../Classes/provider_class.dart';// Import the provider class
import '../Classes/Button_Data.dart';
import 'second_page.dart';


void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => PageProvider(),
      child: MaterialApp(
        home: MainPage(),
      ),
    ),
  );
}


class MainPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // Get the PageProvider instance from the Provider
    PageProvider pageProvider = Provider.of<PageProvider>(context);

    // Now you can access pageProvider.firstPageActiveButtons[1] and other properties

    final List<Button_Data> buttonsData = [
      Button_Data('Check Inventory', pageProvider.firstPageActiveButtons[0]),
      Button_Data('Sell and Collect', pageProvider.firstPageActiveButtons[1]),
      Button_Data('Distribute POSM', pageProvider.firstPageActiveButtons[2]),
      Button_Data('Remit Sales', pageProvider.firstPageActiveButtons[3]),
      Button_Data('Return and Restock', pageProvider.firstPageActiveButtons[4]),
      Button_Data('Get ending Inventory', pageProvider.firstPageActiveButtons[5]),
    ];

    return Scaffold(
      appBar: AppBar(
        title: Text('EX Trucker Tasks'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: buttonsData.map((buttonData) => CustomButton(
            key: PageStorageKey<String>(buttonData.name),
            buttonData: buttonData,
            onTap: () {
              if (buttonData.name == 'Check Inventory') {
                Navigator.pushReplacement(
                  context,
                  MaterialPageRoute(builder: (context) => SecondPage()),
                );
              } else {
                print('Button ${buttonData.name} pressed!');
              }
            },
          )).toList(),
        ),
      ),
    );
  }
}


class CustomButton extends StatelessWidget {
  final Button_Data buttonData;
  final VoidCallback onTap;

  CustomButton({Key? key, required this.buttonData, required this.onTap})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: EdgeInsets.symmetric(vertical: 10),
      child: ElevatedButton(
        onPressed: buttonData.isEnabled ? onTap : null,
        style: ButtonStyle(
          backgroundColor:
          buttonData.isEnabled ? null : MaterialStateProperty.all<Color>(Colors.grey),
        ),
        child: Text(buttonData.name),
      ),
    );
  }
}

second_page.dart

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../Classes/Button_Data.dart';
import 'main.dart';
import 'package:provider/provider.dart';
import '../Classes/provider_class.dart'; // Import the provider class

class SecondPage extends StatefulWidget {
  @override
  _SecondPageState createState() => _SecondPageState();
}

class _SecondPageState extends State<SecondPage>
    with AutomaticKeepAliveClientMixin<SecondPage> {
  late List<Button_Data> secondPageButtonsData;
  bool showReturnButton = false;

  @override
  bool get wantKeepAlive => true;

  @override
  void initState() {
    super.initState();
    initializeSecondPage();
  }

  bool isFirstLoad = true;

  Future<void> initializeSecondPage() async {
    PageProvider pageProvider = Provider.of<PageProvider>(context, listen: false);
    await loadStoredState();

    // Enable buttons up to the active index when the page is loaded for the first time
    if (isFirstLoad) {
      for (int i = 0; i < secondPageButtonsData.length; i++) {
        secondPageButtonsData[i].isEnabled = i <= pageProvider.secondPageActiveButtonIndex;
      }
      showReturnButton = pageProvider.secondPageActiveButtonIndex == secondPageButtonsData.length - 1;
      isFirstLoad = false;
      print('isFirstLoad is true');
    } else {
      print('isFirstLoad is false');
    }
  }

  Future<void> loadStoredState() async {
    secondPageButtonsData = [
      Button_Data('Task 1', true),
      Button_Data('Task 2', false),
      Button_Data('Task 3', false),
      Button_Data('Task 4', false),
      Button_Data('Task 5', false),
    ];

    final prefs = await SharedPreferences.getInstance();

    for (int i = 0; i < secondPageButtonsData.length; i++) {
      Map<String, dynamic>? storedData = await retrieveStoredState(secondPageButtonsData[i].name);
      if (storedData != null) {
        secondPageButtonsData[i].isEnabled = storedData['isEnabled'] ?? false;
      }
    }

    showReturnButton = secondPageButtonsData.last.isEnabled;
  }

  void storeState(Button_Data buttonData) async {
    final prefs = await SharedPreferences.getInstance();
    prefs.setBool('${buttonData.name}_isEnabled', buttonData.isEnabled);
  }

  Future<Map<String, dynamic>?> retrieveStoredState(String buttonName) async {
    final prefs = await SharedPreferences.getInstance();
    bool? isEnabled = prefs.getBool('${buttonName}_isEnabled');
    if (isEnabled != null) {
      return {'isEnabled': isEnabled};
    } else {
      return null;
    }
  }

  @override
  Widget build(BuildContext context) {
    super.build(context);
    PageProvider pageProvider = Provider.of<PageProvider>(context);

    return Scaffold(
      appBar: AppBar(
        title: Text('Check Inventory'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            for (int i = 0; i < secondPageButtonsData.length && pageProvider.isFirstLoad; i++)
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  if (i == pageProvider.secondPageActiveButtonIndex && !showReturnButton)
                    Container(
                      margin: EdgeInsets.only(right: 8.0),
                      width: 8.0,
                      height: 8.0,
                      decoration: BoxDecoration(
                        shape: BoxShape.circle,
                        color: Colors.red,
                      ),
                    ),
                  CustomButton(
                    buttonData: secondPageButtonsData[i],
                    onTap: () {
                      setState(() {
                        if (i == pageProvider.secondPageActiveButtonIndex &&
                            i < secondPageButtonsData.length - 1) {
                          // Check if the correct button is pressed to increment the index
                          pageProvider.setSecondPageActiveButtonIndex(i + 1);
                          secondPageButtonsData[pageProvider.secondPageActiveButtonIndex].isEnabled = true;
                          storeState(secondPageButtonsData[pageProvider.secondPageActiveButtonIndex]);

                          // Change the text on the button to "Task completed"
                          secondPageButtonsData[i].name = 'Task ${pageProvider.secondPageActiveButtonIndex} completed';
                        } else if (i == secondPageButtonsData.length - 1) {
                          // Show 'Return to previous page' button when 'Task 5' is pressed
                          secondPageButtonsData[i].name = 'Task 5 completed';
                          showReturnButton = true;
                        }
                      });
                    },
                  ),
                ],
              ),

            // Other widgets go here

            if (!pageProvider.isFirstLoad) // Show the Text widgets when isFirstLoad is false
              ...[
                Text('Task 1 complete', style: TextStyle(fontSize: 20)),
                Text('Task 2 complete', style: TextStyle(fontSize: 20)),
                Text('Task 3 complete', style: TextStyle(fontSize: 20)),
                Text('Task 4 complete', style: TextStyle(fontSize: 20)),
                Text('Task 5 complete', style: TextStyle(fontSize: 20)),
              ],

            // 'Return to previous page' button
            if ((showReturnButton || !pageProvider.isFirstLoad) )
              ElevatedButton(
                onPressed: () async {
                  await Navigator.pushReplacement(
                    context,
                    MaterialPageRoute(
                      builder: (context) => MainPage(),
                    ),
                  );
                  // Set isFirstLoad to false and notify listeners
                  pageProvider.setIsFirstLoad(false);
                  pageProvider.firstPageActiveButtons[1] = true;
                },
                child: Text('Return to previous page'),
              ),
          ],
        ),
      ),
    );
  }
}

provider_class.dart

import 'package:flutter/material.dart';

class PageProvider extends ChangeNotifier {
  int secondPageActiveButtonIndex = 0;
  int mainPageNoticeIndex = 0;

  // Declare a fixed-length list with a specified size and default values
  List<bool> firstPageActiveButtons = List<bool>.filled(6, false);

  bool isFirstLoad = true; // Added variable to track the first load

  PageProvider() {
    // Initialize the list or set its values in the constructor
    firstPageActiveButtons[0] = true;
    firstPageActiveButtons[1] = false;
    firstPageActiveButtons[2] = false;
    firstPageActiveButtons[3] = false;
    firstPageActiveButtons[4] = false;
    firstPageActiveButtons[5] = false;
  }

  void setSecondPageActiveButtonIndex(int index) {
    secondPageActiveButtonIndex = index;
    notifyListeners();
  }

  void setIsFirstLoad(bool value) {
    isFirstLoad = value; // Update the value of isFirstLoad
    notifyListeners();
  }
}

Button_Data.dart

class Button_Data {
  String name;
  bool isEnabled;

  Button_Data(this.name, this.isEnabled);
}

解决方案

问题核心有两点:

  1. 返回主页面时修改Provider状态的代码放在了Navigator.pushReplacement之后,此时SecondPage已被销毁,Provider的修改无法触发监听更新。
  2. 修改firstPageActiveButtons[1]时未调用notifyListeners(),即使值改变,MainPage也收不到状态变化通知。

步骤1:扩展Provider类的方法

在provider_class.dart中新增专门的方法更新按钮状态并触发通知:

// 在PageProvider类中添加
void enableSellAndCollectButton() {
  firstPageActiveButtons[1] = true;
  notifyListeners(); // 触发所有监听Widget更新
}

步骤2:调整返回按钮的逻辑顺序

在second_page.dart的返回按钮点击事件中,先更新Provider状态,再执行页面跳转:

ElevatedButton(
  onPressed: () async {
    // 先更新Provider状态,再跳转页面
    PageProvider pageProvider = Provider.of<PageProvider>(context, listen: false);
    pageProvider.setIsFirstLoad(false);
    pageProvider.enableSellAndCollectButton(); // 调用新增方法
    
    await Navigator.pushReplacement(
      context,
      MaterialPageRoute(builder: (context) => MainPage()),
    );
  },
  child: Text('Return to previous page'),
),

效果验证

修改后,用户点击返回按钮时,会先更新Provider中的按钮状态并触发通知,再跳转到主页面。MainPage因监听了Provider变化会自动重建,「Sell and Collect」按钮会立即读取到最新的true值,变为启用状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 15:48:10