使用提供程序从第二个屏幕更新脚手架 [英] Use Provider to update Scaffold from a second screen

查看:84
本文介绍了使用提供程序从第二个屏幕更新脚手架的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想要一个设置"屏幕,在这里我可以选择一种颜色以返回到第一个屏幕.

I want to have a Settings screen where I can choose a color to be returned to the first screen.

关闭设置"屏幕后,我无法更新第一个屏幕.

I can't get the first screen to update when the Setting screen is closed.

我正在使用提供者作为更改通知者.但是我看不到如何触发第一个屏幕的更新.第三个按钮创建一个事件来更新屏幕,但是可以自动完成吗?

I'm using the Provider as a change notifier. But I can't see how to trigger the update of the first screen. The third button creates an event which updates the screen, but can this be done automatically?

我想念的是什么...?

What am I missing...?

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

void main() => runApp(MyApp());
Color bgColor = Colors.yellow[100];

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: MyHomeScreen());
  }
}

class MyHomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (context) => ColorModel()),
      ],
      child: Consumer<ColorModel>(builder: (context, colorModel, child) {
        return Scaffold(
          appBar: AppBar(title: Text('Thanks for your help :)')),
          body: Container(
            constraints: BoxConstraints.expand(),
            color: bgColor,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                Text('Change background color on this screen'),

                OutlinedButton(
                  style: OutlinedButton.styleFrom(
                    backgroundColor: Colors.green[600],
                  ),
                  child:
                  Text('Button1', style: TextStyle(color: Colors.white)),
                  onPressed: () {
                    var result = Navigator.push(
                        context, MaterialPageRoute(builder: (context) => Screen2()));
                    print('>>> Button1-onPressed completed, result=$result');
                  },
                ),


                OutlinedButton(
                  style: OutlinedButton.styleFrom(
                    backgroundColor: Colors.green[600],
                  ),
                  child:
                  Text('Choose a colour', style: TextStyle(color: Colors.white)),
                  onPressed: () {
                    asyncButton(context);
                    print('>>> Screen1 Button-onPressed completed');
                  },
                ),

                OutlinedButton(
                  style: OutlinedButton.styleFrom(
                    backgroundColor: Colors.green[600],
                  ),
                  child:
                  Text('Now try me', style: TextStyle(color: Colors.white)),
                  onPressed: () {
                    colorModel.notifyListeners();
                  },
                ),
              ],
            ),
          ),
        );
      }),
    );
  }

  void asyncButton(BuildContext context) async {
    var result = await Navigator.push(
        context, MaterialPageRoute(builder: (context) => Screen2()));
    print('>>> asyncButton completed: result = $result');
    bgColor = result;
  }
}

class ColorModel with ChangeNotifier {
  void updateDisplay() {
    notifyListeners();
  }
}

class Screen2 extends StatelessWidget {
  int _value;
  List<String> names = ['Red', 'Green', 'Blue'];
  List<Color> colors = [Colors.red[100], Colors.green[100], Colors.blue[100]];

  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (context) => ColorModel()),
      ],
      child: Scaffold(
        appBar: AppBar(
          toolbarHeight: 80,
          backgroundColor: Colors.blue,
          title: Center(child: Text('Screen2')),
        ),
        body: Container(
          constraints: BoxConstraints.expand(),
          color: Colors.white,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
              Consumer<ColorModel>(builder: (context, colorModel, child) {
                return DropdownButton(
                  value: _value,
                  hint: Text("Select a color"),
                  focusColor: Colors.lightBlue,
                  onChanged: (int value) {
                    Navigator.pop(context, colors[value]);
                  },
                  items: [
                    DropdownMenuItem(value: 0, child: Text(names[0])),
                    DropdownMenuItem(value: 1, child: Text(names[1])),
                    DropdownMenuItem(value: 2, child: Text(names[2])),
                  ],
                );
              }),
            ],
          ),
        ),
      ),
    );
  }
}

推荐答案

Navigator.push Provider 一起使用时比较棘手.这会导致很多"在此Navigator Widget上方找不到正确的提供程序" 错误.我已经在有关相关问题的答案中解释了原因.

Navigator.push is tricky to use with Provider. It causes a lot of "Could not find the correct Provider above this Navigator Widget" errors. I've explained why in this answer to a related question.

以下是您的情况的简要概述:

Here's a quick overview of your situation:

有问题的代码的建筑:

MaterialApp
 > provider(Screen A)
 > provider(Screen B)

以下解决方案中的体系结构:

Architecture in solution below:

provider(MaterialApp)
 > Screen A
 > Screen B

这是您的代码示例,经过简化,与 Provider 一起使用,从第2页更新了第1页的背景颜色.

Here's your code sample, shortened up, working with Provider, updating the background color on Page 1 from the Page 2.

我在整个代码中都添加了注释,以解释更改.

I've put comments throughout the code to explain changes.

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

// - global var removed -
// Color bgColor = Colors.yellow[100];

void main() {
  runApp(ProviderApp());
}

class ProviderApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    /// Define your Provider here, above MaterialApp
    return ChangeNotifierProvider(
      create: (context) => ColorModel(),
      child: MaterialApp(
          title: 'Flutter Demo',
          debugShowCheckedModeBanner: false,
        home: ScreenA()
      ),
    );
  }
}

class ScreenA extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Thanks for your help :)')),
      body: Container(
        constraints: BoxConstraints.expand(),
        //
        // color: bgColor // - global var removed -
        color: Provider.of<ColorModel>(context).bgColor,
        // ↑ use your Provider state-stored value here ↑
        //
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            Text('Change background color on this screen'),
            OutlinedButton(
              style: OutlinedButton.styleFrom(
                backgroundColor: Colors.green[600],
              ),
              child: Text('Go Screen B', style: TextStyle(color: Colors.white)),
              // Navigator.push returns a Future, must async/await to use return value
              onPressed: () async {
                var result = await Navigator.of(context).push(
                    MaterialPageRoute(builder: (context) => ScreenB()));
                // note that this context is not Screen A context, but MaterialApp context
                // see https://stackoverflow.com/a/66485893/2301224
                print('>>> Button1-onPressed completed, result=$result');
              },
            ),
          ],
        ),
      ),
    );
  }
}

/// This is your state object. Store your state here.
/// Create this once and use anywhere you need.  Don't re-create this unless
/// you want to wipe out all state data you were holding/sharing.
class ColorModel with ChangeNotifier {
  // color is the state info you want to store & share
  Color bgColor = Colors.yellow[100]; // initialized to yellow

  /// Update your state value and notify any interested listeners
  void updateBgColor(Color newColor) {
    bgColor = newColor;
    notifyListeners();
  }

  /// - removed - replaced with updateBgColor ↑
  /*void updateDisplay() {
    notifyListeners();
  }*/
}

class ScreenB extends StatelessWidget {
  // all fields in StatelessWidgets should be final
  //final int value;  // this value isn't needed
  final List<String> names = ['Red', 'Green', 'Blue'];
  final List<Color> colors = [Colors.red[100], Colors.green[100], Colors.blue[100]];

  @override
  Widget build(BuildContext context) {
    /// Instantiating your model & giving it to Provider to should only happen once per
    /// Widget Tree that needs access to that state. e.g. MaterialApp for this solution
    /// The state object & Provider below was repeated & has been commented out / removed.
    /// This was wiping out any previously stored state and creating a new Provider / Inherited scope
    /// to all children.
    /*return MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (context) => ColorModel()),
      ],
      child: ,
    );*/
    // - end of duplicate Provider removal -
    return Scaffold(
      appBar: AppBar(
        title: Text('Screen2'),
      ),
      body: Container(
        alignment: Alignment.center,
        child: Consumer<ColorModel>(builder: (context, colorModel, child) {
          return DropdownButton(
            //value: value, // this value isn't needed
            hint: Text("Select a color"),
            onChanged: (int value) {
              colorModel.updateBgColor(colors[value]);
              Navigator.pop(context, colors[value]);
            },
            items: [
              DropdownMenuItem(value: 0, child: Text(names[0])),
              DropdownMenuItem(value: 1, child: Text(names[1])),
              DropdownMenuItem(value: 2, child: Text(names[2])),
            ],
          );
        }),
      ),
    );
  }
}

这篇关于使用提供程序从第二个屏幕更新脚手架的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆