flutter-web - Eviti che initialRoute si avvii quando l'app viene avviata con un percorso diverso tramite la barra degli indirizzi del browser?
Nuovo in Flutter.
Sto creando un'app con una schermata iniziale che viene visualizzata inizialmente quando l'utente apre l'app. Dopo 3 secondi, l'app mostrerà il login o la schermata del dashboard, a seconda dello stato di autenticazione.
Ecco il mio codice.
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...
}
Ho eseguito il debug dell'app con un server web. Quando l'app viene avviata con l'URL localhost: 8000 /, tutto sembra a posto. Tuttavia, se l'app è stata avviata con l'url localhost: 8000 / notes, la schermata iniziale, penso, viene comunque avviata. Quello che succede è che l'app mostrerà la schermata delle note, quindi dopo 3 secondi l'app aprirà un'altra schermata delle note.
Qualche idea?
Risposte
Poiché il primo rendering inizia sempre alla radice "/", è preferibile utilizzare il proprio percorso per la schermata iniziale, come
initialRoute: '/splash'
.
Per nascondere questo percorso nella barra degli indirizzi, sostituire la mappa dei percorsi con il generatore di percorsi:
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',
);
}
}
Vedi, poiché la logica principale è che non possiamo avere attesa nello stato di inizializzazione, quindi la pagina verrà compilata indipendentemente dalla logica fornita. Ho una soluzione a questo, potrebbero esserci dei progressi o anche altre buone soluzioni, quindi questo è quello che userò.
Userei un concetto di futuro costruttore. Quello che farà è aspettare il mio server e quindi creare l'intera app.
Quindi il processo è
Nel tuo main.dart usa
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 } }
Ora il widget stateless di MyApp che ci aiuterà a scegliere il nostro percorso
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,
);
}
}
}
},
);
}
}
Prima di tutto, flutter-web come qualsiasi altra applicazione a pagina singola supporta il routing basato su hash. Di conseguenza se vuoi accedere
localhost: 8000 / note
devi accedervi come
localhost: 8000 / # / note
Modo più pulito per gestire lo stato di autenticazione
Chiama la funzione getAuthState prima di runApp () per assicurarti che lo stato di autenticazione sia impostato prima che l'app venga inizializzata. E passa authState al widget SplashScreen come parametro.
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(),
),
);
}
}
E se vuoi un modo ancora più pulito per gestire lo stato di autenticazione, devi utilizzare una soluzione di gestione dello stato come Provider.