Przechodzenie do nowego ekranu po zmianie wartości strumienia w bloku
W trzepotaniu jak nazwać nawigatora.push, gdy zmienia się wartość strumienia? Próbowałem poniższego kodu, ale pojawia się błąd.
StreamBuilder(
stream: bloc.streamValue,
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
if (snapshot.hasData && snapshot.data == 1) {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SomeNewScreen()),
);
}
return Text("");
});
2 answers
Nie należy używać StreamBuilder
do obsługi nawigacji.
StreamBuilder
jest używany do budowania zawartości ekranu i nic więcej.
Zamiast tego będziesz musiał słuchać strumienia, aby ręcznie wywołać efekty uboczne. Odbywa się to poprzez użycie StatefulWidget
i nadpisanie initState
/dispose
jako takie:
class Example extends StatefulWidget {
final Stream<int> stream;
const Example({Key key, this.stream}) : super(key: key);
@override
ExampleState createState() => ExampleState();
}
class ExampleState extends State<Example> {
StreamSubscription _streamSubscription;
@override
void initState() {
super.initState();
_listen();
}
@override
void didUpdateWidget(Example oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.stream != widget.stream) {
_streamSubscription.cancel();
_listen();
}
}
void _listen() {
_streamSubscription = widget.stream.listen((value) {
Navigator.pushNamed(context, '/someRoute/$value');
});
}
@override
void dispose() {
_streamSubscription.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container();
}
}
Zwróć uwagę, że jeśli używasz InheritedWidget
do uzyskania strumienia (zazwyczaj BLoC), będziesz chciał użyć didChangeDependencies
zamiast initState
/didUpdateWidget
.
To prowadzi do:
class Example extends StatefulWidget {
@override
ExampleState createState() => ExampleState();
}
class ExampleState extends State<Example> {
StreamSubscription _streamSubscription;
Stream _previousStream;
void _listen(Stream<int> stream) {
_streamSubscription = stream.listen((value) {
Navigator.pushNamed(context, '/someRoute/$value');
});
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
final bloc = MyBloc.of(context);
if (bloc.stream != _previousStream) {
_streamSubscription?.cancel();
_previousStream = bloc.stream;
_listen(bloc.stream);
}
}
@override
void dispose() {
_streamSubscription.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container();
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-01-09 12:16:14
Możesz rozszerzyć StreamBuilder
za pomocą niestandardowego słuchacza w następujący sposób:
typedef StreamListener<T> = void Function(T value);
class StreamListenableBuilder<T> extends StreamBuilder<T> {
final StreamListener<T> listener;
const StreamListenableBuilder({
Key key,
T initialData,
Stream<T> stream,
@required this.listener,
@required AsyncWidgetBuilder<T> builder,
}) : super(key: key, initialData: initialData, stream: stream, builder: builder);
@override
AsyncSnapshot<T> afterData(AsyncSnapshot<T> current, T data) {
listener(data);
return super.afterData(current, data);
}
}
Następnie podłącz słuchacza do nawigacji w ten sposób:
StreamListenableBuilder(
stream: bloc.streamValue,
listener: (value) {
if (value==1) {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SomeNewScreen()),
);
}
},
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
return Container();
});
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-01-28 13:18:12