检测用户是否在Flutter中离开当前页面?

jljoyd4f  于 2022-12-30  发布在  Flutter
关注(0)|答案(6)|浏览(379)

有没有办法检测用户是否离开了当前页面?我不认为WidgetsBinding会起作用,因为它会自己处理这些事件。那么,有人有什么解决办法吗?任何帮助都是感激的。

wfypjpf4

wfypjpf41#

我有一个简单的解决方案,如果你说的“离开页面”是指用户从这个页面“返回”。如果你还想在用户打开当前页面之前的另一个页面时得到通知,下面的解决方案将不起作用。
对于第一种情况,你可以使用WillPopScope,它是一个类,当包含的ModalRoute(由Navigator内部使用)将要弹出时,它会通知你,它甚至让你选择是否要弹出。
只需将第二个屏幕的Scaffold Package 为WillPopScope

return WillPopScope(
  onWillPop: () async {
    // You can do some work here.
    // Returning true allows the pop to happen, returning false prevents it.
    return true;
  },
  child: ... // Your Scaffold goes here.
);
gmol1639

gmol16392#

根据你的描述,我认为你想跟踪你的用户,如果用户按下返回按钮或返回到上一个屏幕。
您可以通过重写State类上的dispose来实现这一点。
希望以下例子能帮助你找到解决方案。

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: EventRow(),
    );
  }
}

class EventRow extends StatelessWidget {

  @override
  Widget build (BuildContext context) {
    return Scaffold(
      appBar: new AppBar(
        title: new Text("Demo"),
      ),
      body: Center(
        child: Container(
          child: new RaisedButton(
            onPressed: (){
              Navigator.push(
                context,
                MaterialPageRoute(builder: (context) => SecondScreen()),
              );
              },
            child: Text("Goto Second Scrren"),
          ),
        ),
      ),
    );
  }

}

class SecondScreen extends StatefulWidget {
  @override
  _SecondScreenState createState() => _SecondScreenState();
}

class _SecondScreenState extends State<SecondScreen> {

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
  }

  @override
  void dispose() {
    // TODO: implement dispose
    print("Back To old Screen");
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: new Center(
        child: new Container(
          child: new RaisedButton(
              child: Text("Goto First Scrren"),
              onPressed: (){
                Navigator.pop(context);
              }
          ),
        ),
      ),
    );
  }
}
83qze16e

83qze16e3#

如果您想检测用户是否离开屏幕,不管是返回(弹出)还是推送另一个上下文,RouteObserver和RouteAware都是一种方法。
这里有一个例子,很抱歉它有点长,如果你试着运行它,你会发现它很简单。

import 'package:flutter/material.dart';

void main() async {
  runApp(App());
}

class App extends StatelessWidget {
  static final RouteObserver<PageRoute> routeObserver =
      RouteObserver<PageRoute>();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      initialRoute: '/',
      navigatorObservers: [routeObserver],
      routes: {
        '/': (context) => Screen1(),
        'screen2': (context) => Screen2(),
      },
    );
  }
}

class ScreenWrapper extends StatefulWidget {
  final Widget child;
  final Function() onLeaveScreen;
  final String routeName;
  ScreenWrapper({this.child, this.onLeaveScreen, @required this.routeName});

  @override
  State<StatefulWidget> createState() {
    return ScreenWrapperState();
  }
}

class ScreenWrapperState extends State<ScreenWrapper> with RouteAware {
  @override
  Widget build(BuildContext context) {
    return widget.child;
  }

  void onLeaveScreen() {
    if (widget.onLeaveScreen != null) {
      widget.onLeaveScreen();
    }
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    App.routeObserver.subscribe(this, ModalRoute.of(context) as PageRoute);
  }

  @override
  void dispose() {
    super.dispose();
    App.routeObserver.unsubscribe(this);
  }

  @override
  void didPush() {
    print('*** Entering screen: ${widget.routeName}');
  }

  void didPushNext() {
    print('*** Leaving screen: ${widget.routeName}');
    onLeaveScreen();
  }

  @override
  void didPop() {
    print('*** Going back, leaving screen: ${widget.routeName}');
    onLeaveScreen();
  }

  @override
  void didPopNext() {
    print('*** Going back to screen: ${widget.routeName}');
  }
}

class Screen1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ScreenWrapper(
      onLeaveScreen: () {
        print("***** Here's my special handling for leaving screen1!!");
      },
      routeName: '/',
      child: Scaffold(
        backgroundColor: Colors.yellow,
        body: SafeArea(
          child: Column(
            children: [
              Text('This is Screen1'),
              FlatButton(
                child: Text('Press here to go to screen 2'),
                onPressed: () {
                  Navigator.pushNamed(context, 'screen2');
                },
              ),
              FlatButton(
                child: Text(
                    "Press here to go back (only works if you've pushed before)"),
                onPressed: () {
                  Navigator.maybePop(context);
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class Screen2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ScreenWrapper(
      routeName: 'screen2',
      child: Scaffold(
        backgroundColor: Colors.blue,
        body: SafeArea(
          child: Column(
            children: [
              Text('This is Screen2'),
              FlatButton(
                child: Text('Press here to go to screen 1'),
                onPressed: () {
                  Navigator.pushNamed(context, '/');
                },
              ),
              FlatButton(
                child: Text(
                    "Press here to go back (only works if you've pushed before)"),
                onPressed: () {
                  Navigator.maybePop(context);
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}
dsekswqp

dsekswqp4#

您可以通过重写dispose()方法来实现这一点。

vxf3dgd4

vxf3dgd45#

我最近遇到了一个情况,我需要检测路线的变化,无论是弹出当前路线还是从当前路线推到新路线,我能够通过从答案here获得的RouteObserver实现这一点。
使用WillPopScope,您可以在路由(pop)发生之前检测到可能的更改,并确定是否应该允许或拒绝它。如果您只是想在pop之后执行某个操作,可以通过重写onDispose来完成。

u7up0aaq

u7up0aaq6#

对于Web部件,使用以下代码检测用户是否处于活动状态

if (kIsWeb) {
      EasyLoading.init();
      window.addEventListener('focus', onFocus);
      window.addEventListener('blur', onBlur);
    } else {
      WidgetsBinding.instance.addObserver(this);
    }

相关问题