如何在flutter应用程序中保存上次打开的屏幕

Gud*_*guy 5 dart flutter

我试图在启动后重新打开上次打开的屏幕,有什么简单的方法吗?欢迎提供示例代码!

到目前为止,我尝试了一个代码(我在某处找到了)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!'),
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

我应该使用SQLite还是JSON代替SharedPreferences使代码简单?谢谢。

eja*_*abu 9

演示

演示

A. 导航

当我们在应用程序内的不同屏幕中导航时,实际上,路由堆栈正在发生变化。

所以,首先,我们需要弄清楚如何监听这种变化,例如推送屏幕,弹出回用户屏幕。

1.在每个动作按钮中附加保存方法

我们实际上可以把它放在每个与导航相关的按钮上。

一种。在抽屉物品上

  ListTile(
    title: Text("Beta"),
    onTap: () {
      saveLastScreen(); // saving to SharedPref here
      Navigator.of(context).pushNamed('/beta'); // then push
    },
  ),

Run Code Online (Sandbox Code Playgroud)

湾 在标题栏后退按钮上

    appBar: AppBar(
    title: Text("Screen"),
    leading: IconButton(
      icon: Icon(Icons.menu),
      onPressed: () {
        saveLastScreen(); // saving to SharedPref here
        Navigator.pop(context); // then pop
      },
    ),
  ),
Run Code Online (Sandbox Code Playgroud)

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"),
        ),
Run Code Online (Sandbox Code Playgroud)

因此,我们将拥有更多的代码并且更难管理。

2. 监听路由变化使用 Route observer

尽管如此,Flutter 在 MaterialApp 上提供了一些“ 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();
        },
Run Code Online (Sandbox Code Playgroud)

我们可以定义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);
  }
}
Run Code Online (Sandbox Code Playgroud)

B. 如何启动应用程序

当用户通过屏幕进行交互时,共享首选项将始终存储最后的路线名称。为了使应用程序相应地导航,我们需要使我们的 BaseScreen 有状态并覆盖其 initState 方法,如下所示:

return MaterialApp(
  routes: {
    '/': (context) {
      return BaseScreen(); // define it as Main Route
    },
Run Code Online (Sandbox Code Playgroud)
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);
    }
  }

Run Code Online (Sandbox Code Playgroud)

C. 工作回购

您可以查看覆盖 RouteObserver 的存储库,如上面第二个选项中所述

在不同的开始保存和打开 Screen Beta 和 Screen Delta

D. 共享首选项 / JSON / SQLite

为简单起见,我建议使用共享首选项。由于我们只记录简单的路由名称String,所以我们只能写两行代码保存和两行代码加载。

如果我们使用 JSON 文件,我们需要使用 package.json 手动为其设置 Path path_provider

此外,如果我们使用 SQLite,我们需要设置 DB(可能包含 > 8 行),以及设置表和插入表的方法。