我试图在引导后重新打开上次打开的屏幕,是否有任何简单的方法?欢迎提供示例代码!
到目前为止,我尝试使用编写了一个代码(到某处)SharedPreferences,但是它不起作用。
SharedPreferences
import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; String lastRouteKey = 'last_route'; void main() async { SharedPreferences preferences = await SharedPreferences.getInstance(); String lastRoute = preferences.getString(lastRouteKey); runApp(MyApp(lastRoute)); } class MyApp extends StatelessWidget { final String lastRoute; MyApp(this.lastRoute); @override Widget build(BuildContext context) { bool hasLastRoute = getWidgetByRouteName(lastRoute) != null; return MaterialApp( home: Foo(), initialRoute: hasLastRoute ? lastRoute : '/', onGenerateRoute: (RouteSettings route) { persistLastRoute(route.name); return MaterialPageRoute( builder: (context) => getWidgetByRouteName(route.name), ); }, ); } Widget getWidgetByRouteName(String routeName) { switch (routeName) { case '/': return MainWidget(); case '/': return SecondRoute(); // Put all your routes here. default: return null; } } void persistLastRoute(String routeName) async { SharedPreferences preferences = await SharedPreferences.getInstance(); preferences.setString(lastRouteKey, routeName); } } class Foo extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Foo'), ), body: Column( children: <Widget>[ RaisedButton( child: Text('Open route second'), onPressed: () { Navigator.push( context, MaterialPageRoute(builder: (context) => SecondRoute()), ); }, ), RaisedButton( child: Text('Open route main'), onPressed: () { Navigator.push( context, MaterialPageRoute(builder: (context) => MainWidget()), ); }, ), ], ), ); } } class SecondRoute extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Second Route"), ), body: Center( child: RaisedButton( onPressed: () { Navigator.pop(context); }, child: Text('Go back!'), ), ), ); } } class MainWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("MainWidget"), ), body: Center( child: RaisedButton( onPressed: () { Navigator.pop(context); }, child: Text('Go back!'), ), ), ); } }
我应该使用SQLite或JSON代替SharedPreferences,使代码简单?谢谢。
SQLite
JSON
实际上,当我们在应用程序中的不同屏幕之间导航时,路线堆栈正在发生变化。
因此,首先,我们需要弄清楚如何收听此更改,例如“推送”屏幕,“弹出回到用户”屏幕。
1.在每个操作按钮中附加保存方法 我们实际上可以将其放在每个与导航相关的按钮上。
一个。抽屉物品
ListTile( title: Text("Beta"), onTap: () { saveLastScreen(); // saving to SharedPref here Navigator.of(context).pushNamed('/beta'); // then push }, ),
b. 在标题栏后退按钮上
appBar: AppBar( title: Text("Screen"), leading: IconButton( icon: Icon(Icons.menu), onPressed: () { saveLastScreen(); // saving to SharedPref here Navigator.pop(context); // then pop }, ), ),
c. 并在Android设备上捕获“电话返回”按钮的事件
@override Widget build(BuildContext context) { return WillPopScope( onWillPop: (){ // will triggered as we click back button saveLastScreen(); // saving to SharedPref here return Future.value(true); }, child: Scaffold( appBar: AppBar( title: Text("Base Screen"), ),
因此,我们将拥有更多的代码,并且将更加难以管理。
尽管如此,Flutter在MaterialApp上提供了一些“ middleware”来捕获路径堆栈中的那些更改。
“ middleware”
我们的MyApp小部件上可能有这个:
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Save Last Route', navigatorObservers: <NavigatorObserver>[ MyRouteObserver(), // this will listen all changes ], routes: { '/': (context) { return BaseScreen(); }, '/alpha': (context) { return ScreenAlpha(); },
我们可以定义MyRouteObserver类如下:
MyRouteObserver
class MyRouteObserver extends RouteObserver { void saveLastRoute(Route lastRoute) async { final SharedPreferences prefs = await SharedPreferences.getInstance(); prefs.setString('last_route', lastRoute.settings.name); } @override void didPop(Route route, Route previousRoute) { saveLastRoute(previousRoute); // note : take route name in stacks below super.didPop(route, previousRoute); } @override void didPush(Route route, Route previousRoute) { saveLastRoute(route); // note : take new route name that just pushed super.didPush(route, previousRoute); } @override void didRemove(Route route, Route previousRoute) { saveLastRoute(route); super.didRemove(route, previousRoute); } @override void didReplace({Route newRoute, Route oldRoute}) { saveLastRoute(newRoute); super.didReplace(newRoute: newRoute, oldRoute: oldRoute); } }
当用户通过屏幕进行交互时,共享首选项将始终 存储最后的路线名称。为了使应用程序进行相应的导航,我们需要 使BaseScreen statefull并覆盖其initState方法,如下所示:
return MaterialApp( routes: { '/': (context) { return BaseScreen(); // define it as Main Route }, class BaseScreen extends StatefulWidget { @override _BaseScreenState createState() => _BaseScreenState(); } class _BaseScreenState extends State<BaseScreen> { @override void initState() { super.initState(); navigateToLastPage(); } void navigateToLastPage() async { final SharedPreferences prefs = await SharedPreferences.getInstance(); String lastRoute = prefs.getString('last_route'); // No need to push to another screen, if the last route was root if (lastRoute.isNotEmpty && lastRoute != '/') { Navigator.of(context).pushNamed(lastRoute); } }
C.工作仓库您可能会看到该存储库覆盖了RouteObserver,如上面第二个选项所述
在不同的开始中保存和打开Screen Beta和Screen Delta
为了简化起见,我建议使用“共享”首选项。由于我们只记录了 简单的String作为路由名称,因此我们只能将两行代码保存到Save中,将 两行代码写入Load。
如果使用JSON文件,则需要使用path_providerpackage 为其手动设置Path 。
path_provider
此外,如果使用SQLite,则需要设置数据库(可能包括多于8行),设置表以及插入表的方法。