Reputation: 9869
I wrote small app that print 1
, 2
, 3
, 42
on splash screen, then wait 2 seconds and complete switching to HomePage
. The problem that I can't figure out how to use Navigator outside of Widget, because it's require context
.
Here is my code:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
Stream<int> stream;
StreamController<int> myStreamController = StreamController();
void main() {
MyClass myClass = MyClass();
WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeLeft])
.then((_) {
runApp(new MyApp());
});
}
class MyClass {
MyClass() {
stream = Stream<int>.periodic(Duration(seconds: 1), (t) => t + 1).take(3);
myStreamController.addStream(stream).then(
(done) {
Future.delayed(Duration(seconds: 2), () { // wait 2 seconds before Showing HomePage
myStreamController.addStream( Stream.value(42) );
// Navigator.push(context, route) // But we do not have context in this class!!
});
}
);
// stream.pipe(myStreamController.sink);
}
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(title: "Hello", routes: {
'/': (context) => SplashScreen(),
'/home': (context) => HomePage(),
});
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context)
{
return Scaffold(
appBar: AppBar(),
body: Container(
child: Text("Hello World, Home Page"),
),
);
}
}
class SplashScreen extends StatefulWidget {
@override
SplashScreenState createState() => SplashScreenState();
}
class SplashScreenState extends State<SplashScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Container(
child: DefaultTextStyle(
style: TextStyle(
fontSize: 24,
color: Colors.black54
),
child: StreamBuilder(
stream: myStreamController.stream,
builder: (context, snapshot) {
if (snapshot.hasData) {
switch (snapshot.data) {
case 1:
return Text("${snapshot.data}");
case 2:
return Text("${snapshot.data}");
case 3:
return Text("${snapshot.data}");
default:
return Text("${snapshot.data}");
}
} else
return CircularProgressIndicator();
})
)
),
));
// return
}
}
class DigitProgressIndicator extends StatelessWidget
{
String text;
DigitProgressIndicator(this.text);
@override
Widget build(BuildContext context)
{
return Text(text);
}
}
Upvotes: 1
Views: 1508
Reputation: 9869
I found two ways to do to do switching screen from business logic. The first one (I think best).
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
Stream<int> stream;
StreamController<int> myStreamController = StreamController.broadcast();
void main() {
MyClass myClass = MyClass();
WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeLeft])
.then((_) {
runApp(new MyApp());
});
}
class MyClass {
MyClass() {
stream = Stream<int>.periodic(Duration(seconds: 1), (t) => t + 1).take(3);
myStreamController.addStream(stream).then(
(done) {
Future.delayed(Duration(seconds: 2), () { // wait 2 seconds before Showing HomePage
myStreamController.addStream( Stream.value(42) );
});
}
);
}
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(title: "Hello",
routes:
{
'/': (context) => SplashScreen(),
'/home': (context) => HomePage(),
},
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context)
{
return Scaffold(
appBar: AppBar(),
body: Container(
child: Text("Hello World, Home Page"),
),
);
}
}
class SplashScreen extends StatefulWidget {
@override
SplashScreenState createState() => SplashScreenState();
}
class SplashScreenState extends State<SplashScreen> {
@override
void initState() {
myStreamController.stream.listen((data) {
if (data == 42)
{
Navigator.pushNamed(context, '/home');
}
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Container(
child: DefaultTextStyle(
style: TextStyle(
fontSize: 24,
color: Colors.black54
),
child: StreamBuilder(
stream: myStreamController.stream,
builder: (context, snapshot) {
if (snapshot.hasData) {
switch (snapshot.data) {
case 1:
return Text("${snapshot.data}");
case 2:
return Text("${snapshot.data}");
case 3:
return Text("${snapshot.data}");
default:
return Text("${snapshot.data}");
}
} else
return CircularProgressIndicator();
})
)
),
));
}
}
The second way is described here http://stacksecrets.com/flutter/navigation-when-there-is-no-context
Upvotes: 1
Reputation: 3111
Just move it to where you display your 42:
class SplashScreenState extends State<SplashScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Container(
child: DefaultTextStyle(
style: TextStyle(
fontSize: 24,
color: Colors.black54
),
child: StreamBuilder(
stream: myStreamController.stream,
builder: (context, snapshot) {
if (snapshot.hasData) {
switch (snapshot.data) {
case 1:
return Text("${snapshot.data}");
case 2:
return Text("${snapshot.data}");
case 3:
return Text("${snapshot.data}");
default:
Navigator.push(context, route); // But now we have context in this class!!
return Text("${snapshot.data}");
}
} else
return CircularProgressIndicator();
})
)
),
));
// return
}
}
you can also wrap the Navigator
with Future.delayed
so it will display the 42 for a while.
also a tip:
Navigator
is a widget, not a Management class, Navigator.of(context)
will get you the nearest ancestor Navigator
widget. pushing
a scaffold on a Navigator
widget means that you are adding a widget on top of it's Stack
widget with Scaffold
children.
Upvotes: 0