【问题标题】:Flutter - How to change the text in bottom navigation from child widget?Flutter - 如何从子小部件更改底部导航中的文本?
【发布时间】:2019-09-06 07:51:22
【问题描述】:

我最近开始使用 Flutter,我的应用需要底部导航。我已经创建了底部导航并设法根据所选选项卡访问子小部件。

在子小部件下有一个下拉选择,我可以在其中更改其中一个选项卡中的底部导航文本以进行不同的选择。

我已经尝试了几天,但仍然无法弄清楚子小部件如何更改文本。

我尝试过回调,但无法正常工作。我已经尝试了 navigation.push - 材料页面路由,但它重建了整个小部件并且我的选择消失了。我还尝试使用 GlobalKey 或 Sharedpreference 来捕获我的选择,这样当它重建时,它将使用存储的选择,但我无法让它工作。

我只希望从子小部件下拉选择中更改其中一个文本中的底部导航文本。

实现这一目标的最佳方法是什么?

【问题讨论】:

    标签: flutter bottomnavigationview


    【解决方案1】:

    我建议您尝试将 bloc 模式与 StreamBuilder 一起使用。我有一个下面的例子。无论如何,在示例中,有一个有状态的小部件、一个块和一个数据类。尝试理解此代码并根据您的需要对其进行修改。

    import 'package:flutter/material.dart';
    import 'dart:async';
    
    class StreamScaffold extends StatefulWidget {
      @override
      _StreamScaffoldState createState() => _StreamScaffoldState();
    }
    
    class _StreamScaffoldState extends State<StreamScaffold> {
      ScaffoldDataBloc bloc;
    
      @override
      void initState() {
        super.initState();
        bloc = ScaffoldDataBloc();
      }
    
      @override
      Widget build(BuildContext context) {
        return StreamBuilder<ScaffoldDataState>(
            stream: bloc.stream, // The stream we want to listen to.
            initialData: bloc.initial(), // The initial data the stream provides.
            builder: (context, snapshot) {
              ScaffoldDataState state = snapshot.data;
    
              Widget page;
              if (state.index == 0) {
                // TODO separate this into its own widget, this is messy.
                page = Center(
                  child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: <Widget>[
                        RaisedButton(
                          onPressed: () => bloc.updateText(state,"Sales"),
                            child: Text("Set text to Sales")
    
                        ),
                        RaisedButton(
                          onPressed: () => bloc.updateText(state, "Purchases"),
                          child: Text("Set text to Purchases"),
                        )
                      ]),
                );
              }
    
              if (state.index == 1) {
                // TODO separate this into its own widget, this is messy.
                page = Center(
                    child: Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: <Widget>[
                      RaisedButton(
                        onPressed: () => bloc.updateText(state, "Stock"),
                        child: Text("Set text to Stock"),
                      ),
                      RaisedButton(
                        onPressed: () => bloc.updateText(state, "Budget"),
                        child: Text("Set text to Budget"),
                      )
                    ]));
              }
    
              return Scaffold(
                body: page,
                bottomNavigationBar: BottomNavigationBar(
                    currentIndex: state.index,
                    onTap: (int) => bloc.updateIndex(state, int),
                    items: [
                      BottomNavigationBarItem(
                          icon: Icon(Icons.play_arrow),
                          // Obtain the text from the state
                          title: Text(state.variableText)),
                      BottomNavigationBarItem(
                          icon: Icon(Icons.play_arrow), title: Text("Test")),
                    ]),
              );
            });
      }
    
      @override
      void dispose() {
        super.dispose();
        bloc.dispose();
      }
    }
    
    // A data class to hold the required data.
    class ScaffoldDataState {
      int index;
      String variableText;
    
      ScaffoldDataState({this.index = 0, this.variableText = "Hello"});
    }
    
    // A bloc to handle updates of the state.
    class ScaffoldDataBloc {
      StreamController<ScaffoldDataState> scaffoldDataStateController = StreamController<ScaffoldDataState>();
      Sink get updateScaffoldDataState => scaffoldDataStateController.sink;
      Stream<ScaffoldDataState> get stream => scaffoldDataStateController.stream;
    
      ScaffoldDataBloc();
    
      ScaffoldDataState initial() {
        return ScaffoldDataState();
      }
    
      void dispose() {
        scaffoldDataStateController.close();
      }
    
      // Needs to be called every time a change should happen in the UI
      // Add updated states into the Sink to get the Stream to update.
      void _update(ScaffoldDataState state) {
        updateScaffoldDataState.add(state);
      }
    
      // Specific methods for updating the different fields in the state object
      void updateText(ScaffoldDataState state, String text) {
        state.variableText = text;
        _update(state);
      }
    
      void updateIndex(ScaffoldDataState state, int index) {
        state.index = index;
        _update(state);
      }
    }
    

    希望对你有帮助!

    评论中的其他问题:

    最简单的解决方案是简单地将块作为参数传递给小部件。在你的项目中创建一个新的 dart 文件,在那里创建一个 StatelessWidget,在 build 方法中为页面创建代码。注意:将 bloc 与数据类一起分离到自己的文件中是有意义的。

    import 'package:flutter/material.dart';
    
    // Import the file where the bloc and data class is located
    // You have to have a similar import in the parent widget. 
    // Your dart files should be located in the lib folder, hit ctrl+space for 
    // suggestions while writing an import, or alt+enter on a unimported class.
    import 'package:playground/scaffold_in_stream_builder.dart'; 
    
    
    class ChildPage extends StatelessWidget {
      final ScaffoldDataBloc bloc;
      final ScaffoldDataState state;
    
      const ChildPage({Key key, this.bloc, this.state}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Container(); // TODO replace with your page
      }
    }
    

    但是,如果这些子小部件在单独的文件中获得自己的子小部件,则最好使用 InheritedWidget 来代替,并带有 bloc 和 state。这避免了“传递状态”。看到这个article on inherited widgets

    【讨论】:

    • 谢谢。有用。如果我要将小部件页面放入另一个文件中它自己的小部件中,可以这样做吗?不同的导航底部标签将具有不同的编码并且可能很长。子小部件如何访问另一个文件中的 bloc.updateText(state,"Sales") ?如果我将它放在另一个文件中,它会显示“bloc”和“state”未定义名称。
    • 谢谢。我使用您的代码并在另一个 dart 文件上使用方法 updateText(state, "sales") 时遇到以下错误。状态为“空”。颤动:在处理手势时引发以下 NoSuchMethodError:颤动:方法“updateText”在 null 上调用。颤振:接收者:空颤振:尝试调用:updateText(null,“Sales”)
    • 主dart文件中的ChildPage的参数中是否传递了state和bloc?喜欢:ChildPage(bloc: bloc, state: state)
    • 是的。以上是更新文件中的代码。谢谢。
    • 太棒了?没问题?
    猜你喜欢
    • 1970-01-01
    • 2021-10-02
    • 1970-01-01
    • 1970-01-01
    • 2021-04-30
    • 1970-01-01
    • 2018-10-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多