代码之家  ›  专栏  ›  技术社区  ›  Vincent

如何使用flatter编写按下双返回按钮退出应用程序

  •  2
  • Vincent  · 技术社区  · 6 年前

    第一次按“后退”按钮时,应用程序将显示一个祝酒词“再次按可退出应用程序”。 当然,两次按压之间的时间不能太长。

    1 回复  |  直到 6 年前
        1
  •  78
  •   VipiN Negi    5 年前

    这是我的一个代码示例(我使用“fluttoast”来显示toast消息,您可以使用snackbar或alert或其他任何东西)

    DateTime currentBackPressTime;
    
    @override
    Widget build(BuildContext context) {
      return Scaffold(
        ...
        body: WillPopScope(child: getBody(), onWillPop: onWillPop),
      );
    }
    
    Future<bool> onWillPop() {
        DateTime now = DateTime.now();
        if (currentBackPressTime == null || 
            now.difference(currentBackPressTime) > Duration(seconds: 2)) {
          currentBackPressTime = now;
          Fluttertoast.showToast(msg: exit_warning);
          return Future.value(false);
        }
        return Future.value(true);
      }
    
        2
  •  23
  •   Hugo Passos    4 年前

    你可以试试 this 包裹

    Scaffold 包装所有小部件后,将 DoubleBackToCloseApp 通过小吃条:

    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            body: DoubleBackToCloseApp(
              child: Home(),
              snackBar: const SnackBar(
                content: Text('Tap back again to leave'),
              ),
            ),
          ),
        );
      }
    }
    

    旧答案

    您还可以选择涉及以下内容的解决方案: SnackBar . 这不是那么简单 Andrey Turkovsky

    class _FooState extends State<Foo> {
      static const snackBarDuration = Duration(seconds: 3);
    
      final snackBar = SnackBar(
        content: Text('Press back again to leave'),
        duration: snackBarDuration,
      );
    
      DateTime backButtonPressTime;
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          // The BuildContext must be from one of the Scaffold's children.
          body: Builder(
            builder: (context) {
              return WillPopScope(
                onWillPop: () => handleWillPop(context),
                child: Text('Place your child here'),
              );
            },
          ),
        );
      }
    
      Future<bool> handleWillPop(BuildContext context) async {
        final now = DateTime.now();
        final backButtonHasNotBeenPressedOrSnackBarHasBeenClosed =
            backButtonPressTime == null ||
                now.difference(backButtonPressTime) > snackBarDuration;
    
        if (backButtonHasNotBeenPressedOrSnackBarHasBeenClosed) {
          backButtonPressTime = now;
          Scaffold.of(context).showSnackBar(snackBar);
          return false;
        }
    
        return true;
      }
    }
    
        3
  •  3
  •   Purushotam Kumar    4 年前

    不幸的是,它们都不适合我,我已经编写了一个通用类(widget)来处理双击退出。如果有人感兴趣

    class DoubleBackToCloseWidget extends StatefulWidget {
      final Widget child; // Make Sure this child has a Scaffold widget as parent.
    
      const DoubleBackToCloseWidget({
        @required this.child,
      });
    
      @override
      _DoubleBackToCloseWidgetState createState() =>
          _DoubleBackToCloseWidgetState();
    }
    
    class _DoubleBackToCloseWidgetState extends State<DoubleBackToCloseWidget> {
      int _lastTimeBackButtonWasTapped;
      static const exitTimeInMillis = 2000;
    
      bool get _isAndroid => Theme.of(context).platform == TargetPlatform.android;
    
      @override
      Widget build(BuildContext context) {
        if (_isAndroid) {
          return WillPopScope(
            onWillPop: _handleWillPop,
            child: widget.child,
          );
        } else {
          return widget.child;
        }
      }
    
      Future<bool> _handleWillPop() async {
        final _currentTime = DateTime.now().millisecondsSinceEpoch;
    
        if (_lastTimeBackButtonWasTapped != null &&
            (_currentTime - _lastTimeBackButtonWasTapped) < exitTimeInMillis) {
          Scaffold.of(context).removeCurrentSnackBar();
          return true;
        } else {
          _lastTimeBackButtonWasTapped = DateTime.now().millisecondsSinceEpoch;
          Scaffold.of(context).removeCurrentSnackBar();
          Scaffold.of(context).showSnackBar(
            _getExitSnackBar(context),
          );
          return false;
        }
      }
    
      SnackBar _getExitSnackBar(
        BuildContext context,
      ) {
        return SnackBar(
          content: Text(
            'Press BACK again to exit!',
            color: Colors.white,
          ),
          backgroundColor: Colors.red,
          duration: const Duration(
            seconds: 2,
          ),
          behavior: SnackBarBehavior.floating,
        );
      }
    }
    
    

    按以下方式使用该类:

    class Dashboard extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return SafeArea(
          child: Scaffold(
            body: DoubleBackToCloseWidget(
              child: Container(
                child: Column(
                  children: [
                    const Text('Hello there'),
                    const Text('Hello there again'),
                  ],
                ),
              ),
            ),
          ),
        );
      }
    }
    
    
    
        4
  •  2
  •   mewadaarvind    5 年前

    第一次按后退按钮时,应用程序显示一个警报对话框“按是退出应用程序,按否无法退出应用程序”。 这是我的代码示例(我使用了“AlertDialog”)

       @override
          Widget build(BuildContext context) {
    
            return new WillPopScope(
              onWillPop: _onBackPressed,
              child: DefaultTabController(
                initialIndex: _selectedIndex,
                length: choices.length,
                child: Scaffold(
                  appBar: AppBar(
    
                    ),
                  ),
    
              ),
            );
          }
             Future<bool> _onBackPressed() {
            return showDialog(
              context: context,
              builder: (context) {
                return AlertDialog(
                  title: Text('Are you sure?'),
                  content: Text('Do you want to exit an App'),
                  actions: <Widget>[
                    FlatButton(
                      child: Text('No'),
                      onPressed: () {
                        Navigator.of(context).pop(false);
                      },
                    ),
                    FlatButton(
                      child: Text('Yes'),
                      onPressed: () {
                        Navigator.of(context).pop(true);
                      },
                    )
                  ],
                );
              },
            ) ?? false;
          }
    
        5
  •  2
  •   Kennedy Owusu    4 年前

    这是我的答案。我使用AlertDialog()实现了这一点

     @override
      Widget build(BuildContext context) {
        return new WillPopScope(
          onWillPop: _onBackPressed,
          child: Scaffold(
            appBar: AppBar(),
            body: Container(),
          ),
        );
      }
      Future<bool> _onBackPressed() {
        return showDialog(
          context: context,
          builder: (context) {
            return AlertDialog(
              title: Text('Confirm'),
              content: Text('Do you want to exit the App'),
              actions: <Widget>[
                FlatButton(
                  child: Text('No'),
                  onPressed: () {
                    Navigator.of(context).pop(false); //Will not exit the App
                  },
                ),
                FlatButton(
                  child: Text('Yes'),
                  onPressed: () {
                    Navigator.of(context).pop(true); //Will exit the App
                  },
                )
              ],
            );
          },
        ) ?? false;
      }
    
        6
  •  2
  •   vidhyesh    4 年前

    只需使用double_back_关闭应用程序库即可

    https://pub.dev/packages/double_back_to_close_app

    将double_back_添加到pubspec.yaml文件中依赖项下的_close_应用程序中

    dependencies:
      double_back_to_close_app: ^1.2.0
    

    这里是示例代码

    import 'package:double_back_to_close_app/double_back_to_close_app.dart';
    import 'package:flutter/material.dart';
    
    void main() => runApp(Example());
    
    class Example extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            body: DoubleBackToCloseApp(
              snackBar: const SnackBar(
                content: Text('Tap back again to leave'),
              ),
              child: Center(
                child: OutlineButton(
                  child: const Text('Tap to simulate back'),
                  // ignore: invalid_use_of_protected_member
                  onPressed: WidgetsBinding.instance.handlePopRoute,
                ),
              ),
            ),
          ),
        );
      }
    }
    

    只需将您的身体内容移动到“DoubleBackToCloseApp”的孩子

        7
  •  1
  •   Marouane M.    4 年前

    如果您想要一个snackbar,您应该提供一个scaffold键,因为它与scaffold相关,所以这个键应该能够在它的scaffold父级之外调用snackbar。

    以下是一个解决方案:

    class Home extends StatelessWidget {
    
      final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
    
      @override
      Widget build(BuildContext context) {
      return WillPopScope(
        onWillPop: () async{
            DateTime initTime = DateTime.now();
            popped +=1;
            if(popped>=2) return true;
            await _scaffoldKey.currentState.showSnackBar(
            SnackBar(
                behavior: SnackBarBehavior.floating,
                content: Text('Tap one more time to exit.',textAlign: TextAlign.center,),
                duration: Duration(seconds: 2),
            )).closed;
    
            // if timer is > 2 seconds reset popped counter
            if(DateTime.now().difference(initTime)>=Duration(seconds: 2)) {
            popped = 0;
            }
            return false;
            },
        child: Scaffold(
            key: _scaffoldKey,
            appBar: AppBar(title : Text("Demo")),
            body: Text("body")
        );
      )
    }
    
    
        8
  •  1
  •   Definev    4 年前

    这是我的解决方案,您可以将backPressTotal值更改为所需的按下次数!

    int backPressCounter = 0;
    int backPressTotal = 2;
    
    @override
    Widget build(BuildContext context) {
      return Scaffold(
        ...
        body: WillPopScope(child: getBody(), onWillPop: onWillPop),
      );
    }
    
    Future<bool> onWillPop() {
        if (backPressCounter < 2) {
          Fluttertoast.showToast(msg: "Press ${backPressTotal - backPressCounter} time to exit app");
          backPressCounter++;
          Future.delayed(Duration(seconds: 1, milliseconds: 500), () {
            backPressCounter--;
          });
          return Future.value(false);
        } else {
          return Future.value(true);
        }
    }
    
        9
  •  1
  •   Omar Alshyokh    4 年前

    如果要增加单击次数,可以使用此解决方案。用户必须在两秒内按3次才能离开

      DateTime currentBackPressTime;
      /// init counter of clicks
      int pressCount=1;
    

    然后:

    Future<bool> onWillPop() async {
    
      DateTime now = DateTime.now();
    
    
    
    /// here I check if number of clicks equal 3
    if(pressCount!=3){
    
      ///should be assigned at the first click.
      if(pressCount ==1 )
        currentBackPressTime = now;
      pressCount+=1;
    
    
      return Future.value(false);
      }else{
      if (currentBackPressTime == null ||
          now.difference(currentBackPressTime) > Duration(seconds: 2)) {
    
    
        currentBackPressTime = now;
        pressCount=0;
    
      
        return Future.value(false);
      }
     }
    
    
     return Future.value(true);
    }