我最近启动了Flutter,我的应用需要底部导航。我已经创建了底部导航,并根据选定的选项卡设法访问了子窗口小部件。
在子小部件下有一个下拉选择,在其中我可以更改选项卡之一中的底部导航文本以进行不同选择。
我尝试了几天,但仍无法弄清楚子控件如何更改文本。
我尝试了回调,但是无法正常工作。我尝试了navigation.push-物料页面路线,但它重建了整个小部件,我的选择消失了。我还尝试使用GlobalKey或Sharedpreference捕获我的选择,以便在重建时,它将使用已存储的选择,但无法正常工作。
我只希望在子窗口小部件下拉选择的文本之一中更改底部导航文本。
哪个是实现此目标的最佳方法?
答案 0 :(得分:0)
我建议您尝试在StreamBuilder中使用bloc模式。我下面有一个例子。无论如何,在该示例中,都有一个有状态的小部件,一个块和一个数据类。尝试理解此代码,并根据需要对其进行修改。
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);
}
}
希望有帮助!
评论中的其他问题:
最简单的解决方案是将bloc作为参数传递给小部件。在您的项目中创建一个新的dart文件,在其中创建一个StatelessWidget,在build方法中为该页面创建代码。注意:将块与数据类一起分成自己的文件对您来说很有意义。
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
}
}
但是,如果这些子窗口小部件在单独的文件中获得了自己的子窗口,则最好使用带有locate和state的InheritedWidget。这避免了“传递状态下降”。查看此article on inherited widgets