检测用户是否将当前页面留在Flutter中?

Two*_*San 6 flutter

有什么方法可以检测用户是否离开当前页面?我认为这WidgetsBinding不会起作用,因为它可以自行处理这些事件。那么,有人有什么解决方案吗?任何帮助表示赞赏。

Mar*_*cel 14

如果“离开页面”是指用户从该页面“返回”,我有一个简单的解决方案。如果您还想在用户打开当前页面之前的另一个页面时收到通知,则以下解决方案将不起作用。

对于第一种情况,您可以使用WillPopScope。这是一个在封闭ModalRoute(由 内部使用Navigator)即将弹出时通知您的类。它甚至让您可以选择是否希望流行音乐发生。

只需将第二个屏幕包装ScaffoldWillPopScope.

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.
);
Run Code Online (Sandbox Code Playgroud)

  • WillPopScope() 对我来说根本不起作用。没有错误,什么都没有。在“return true;”之前使用“print()”,我确认它甚至没有达到。 (2认同)

Vir*_*iya 11

根据您的描述,我认为您想在用户按下后退按钮或返回上一屏幕时跟踪您的用户。

您可以通过覆盖类dispose上的来实现这一点State

可以以下示例帮助您找出解决方案。

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


小智 6

RouteObserver 和 RouteAware 如果您想检测用户是否离开屏幕,无论是返回(弹出)还是推送另一个上下文,都可以使用 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));
  }

  @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);
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)