flutter-web - Избегать инициализации initialRoute, когда приложение запускается с другим маршрутом через адресную строку браузера?
Впервые во Flutter.
Я создаю приложение, в котором есть экран-заставка, который изначально появляется, когда пользователь открывает приложение. Через 3 секунды приложение покажет логин или экран панели инструментов, в зависимости от состояния аутентификации.
Вот мой код.
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...
}
Отлаживаю приложение с помощью веб-сервера. Когда приложение запускается с URL-адресом localhost: 8000 /, все в порядке. Однако, если приложение запускается с url localhost: 8000 / notes, заставка, я думаю, все равно запускается. Что происходит, так это то, что приложение отображает экран заметок, а затем через 3 секунды приложение открывает еще один экран заметок.
Есть идеи?
Ответы
Поскольку первый рендеринг всегда начинается с корня '/', предпочтительно использовать свой собственный путь для экрана-заставки, например
initialRoute: '/splash'
.
Чтобы скрыть этот путь в адресной строке, заменить маршруты карты с генератором маршрута:
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',
);
}
}
Смотрите, поскольку основная логика заключается в том, что мы не можем ожидать в состоянии инициализации, поэтому страница будет строиться независимо от любой логики, которую вы предоставляете. У меня есть решение, может быть какое-то продвижение или другие хорошие решения, так что это то, что я бы использовал.
Я бы использовал концепцию будущего строителя. Что он сделает, так это дождется моего сервера, а затем создаст все приложение.
Итак, процесс
В вашем 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 } }
Теперь виджет без сохранения состояния MyApp, который поможет нам выбрать наш путь
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,
);
}
}
}
},
);
}
}
Прежде всего, flutter-web, как и любое другое одностраничное приложение, поддерживает маршрутизацию на основе хэша. В результате, если вы хотите получить доступ
localhost: 8000 / примечания
вы должны получить к нему доступ как
локальный: 8000 / # / примечания
Более чистый способ обработки состояния аутентификации
Вызовите функцию getAuthState перед runApp (), чтобы убедиться, что состояние аутентификации установлено до инициализации приложения. И передайте authState виджету SplashScreen в качестве параметра.
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(),
),
);
}
}
И если вам нужен еще более чистый способ обработки состояния аутентификации, вам нужно использовать решение для управления состоянием, такое как Provider.