flutter-web - ¿Evitar que initialRoute se inicie cuando la aplicación se inicia con una ruta diferente a través de la barra de direcciones del navegador?
Nuevo en Flutter.
Estoy creando una aplicación que tiene una pantalla de presentación que aparece inicialmente cuando el usuario abre la aplicación. Después de 3 segundos, la aplicación mostrará el inicio de sesión o la pantalla del tablero, según el estado de autenticación.
Aquí está mi código.
main.dart
void main() {
runApp(myApp);
}
MaterialApp myApp = MaterialApp(
initialRoute: "/",
routes: {
"/": (context) => SplashScreen(),
"/signin": (context) => SignInScreen(),
"/notes": (context) => NotesScreen(),
},
);
splash_screen.dart
class SplashScreen extends StatefulWidget {
@override
_SplashScreenState createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
@override
void initState() {
super.initState();
_goToNextScreen();
}
void _goToNextScreen() {
Future.delayed(
Duration(seconds:3),
() async {
AuthState authState = await Auth.getAuthState();
String route = authState == AuthState.SIGNED_IN ? "/notes" : "/signin";
Navigator.pushReplacementNamed(context, route);
}
);
}
// build() override goes here...
}
He estado depurando la aplicación con un servidor web. Cuando la aplicación se inicia con la url localhost: 8000 /, todo parece estar bien. Sin embargo, si la aplicación comenzó con la url localhost: 8000 / notes, creo que la pantalla de presentación aún se inicia. Lo que sucede es que la aplicación mostrará la pantalla de notas, luego, después de 3 segundos, la aplicación abrirá otra pantalla de notas.
¿Algunas ideas?
Respuestas
Debido a que el primer renderizado siempre comienza en la raíz '/', es preferible usar su propia ruta para la pantalla de bienvenida, como
initialRoute: '/splash'
.
Para ocultar esta ruta en la barra de direcciones, reemplace el mapa de rutas con el generador de rutas:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
onGenerateRoute: (RouteSettings settings) {
// print current route for clarity.
print('>>> ${settings.name} <<<');
switch (settings.name) {
case '/splash':
return MaterialPageRoute(
builder: (context) => SplashScreen(),
// settings omitted to hide route name
);
case '/signin':
return MaterialPageRoute(
builder: (context) => SignInScreen(),
settings: settings,
);
case '/notes':
return MaterialPageRoute(
builder: (context) => NotesScreen(),
settings: settings,
);
case '/':
// don't generate route on start-up
return null;
default:
return MaterialPageRoute(
builder: (context) => FallbackScreen(),
);
}
},
initialRoute: '/splash',
);
}
}
Vea, ya que la lógica principal es que no podemos esperar en el estado de inicio, por lo que la página se construirá independientemente de la lógica que proporcione. Tengo una solución para esto, puede haber algún avance u otras buenas soluciones también, así que esto es lo que usaría.
Usaría un concepto de futuro constructor. Lo que hará es esperar mi servidor y luego compilar la aplicación completa.
Entonces el proceso es
En su uso main.dart
Future<void> main() async { try { WidgetsFlutterBinding.ensureInitialized(); //await for my server code and according to the variable I get I will take action //I would have a global parameter lets say int InternetOff await checkServer(); runApp(MyApp()); } catch (error) { print(error); print('Locator setup has failed'); //I can handle the error here } }
Ahora Widget sin estado de MyApp que nos ayudará a elegir nuestro camino
class MyApp extends Stateless Widget{
Widget build(BuildContext context) {
//Using this FutureBuilder
return FutureBuilder<String>(
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
// AsyncSnapshot<Your object type>
// Now if InternetOff is equal to one I would make it go to home
if(InternetOff==1) return MaterialApp(
theme: ThemeData.light(),
home: CheckInternet(),
debugShowCheckedModeBanner: false,
);
//else go to Home similarly with these if and else you can add more conditions
else {
return MaterialApp(
theme: ThemeData.dark(),
home: UserHome(),
debugShowCheckedModeBanner: false,
);
}
}
}
},
);
}
}
En primer lugar, flutter-web como cualquier otra aplicación de página única admite el enrutamiento basado en hash. Como resultado, si desea acceder
localhost: 8000 / notas
tienes que acceder a él como
localhost: 8000 / # / notas
Manera más limpia de manejar el estado de autenticación
Llame a la función getAuthState antes de runApp () para asegurarse de que el estado de autenticación esté establecido antes de que se inicialice la aplicación. Y pase authState al widget SplashScreen como parámetro.
void main() {
WidgetsFlutterBinding.ensureInitialized();
AuthState authState = await Auth.getAuthState();
runApp(MaterialApp myApp = MaterialApp(
initialRoute: "/",
routes: {
"/": (context) => SplashScreen(authState: authState),
"/signin": (context) => SignInScreen(),
"/notes": (context) => NotesScreen(),
},
));
}
splash_screen.dart
class SplashScreen extends StatefulWidget {
final AuthState authState;
SplashScreen({Key key, this.authState}) : super(key: key);
@override
_SplashScreenState createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
@override
void initState() {
super.initState();
_goToNextScreen();
}
void _goToNextScreen() {
Future.delayed(
Duration(seconds:3),
() async {
String route = widget.authState == AuthState.SIGNED_IN ? "/notes" : "/signin";
Navigator.pushReplacementNamed(context, route);
}
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
}
}
Y si desea una forma aún más limpia de manejar el estado de autenticación, debe usar una solución de administración de estado como Provider.