Как я могу разделить одно нажатие и двойное нажатие кнопки возврата во флаттере?

Я пытаюсь сделать функцию выхода из приложения, когда дважды нажимаю кнопку возврата в CupertinoTabbar.

Хотя я применил различные функции, такие как DoubleBackToCloseApp плагин или WillPopScope, всякий раз, когда я нажимаю кнопку "Назад", появлялось сообщение о выходе.

Следовательно, я хочу создать код, работающий следующим образом:

  • просто нажмите кнопку назад один раз, вернитесь перед страницами
  • нажмите дважды в течение нескольких секунд, выйдите из приложения.

моя панель вкладок следующая:

class TabPage extends StatefulWidget {

  final FirebaseUser currentUser;

  TabPage(this.currentUser);

  @override
  _TabPageState createState() => _TabPageState();
}

class _TabPageState extends State<TabPage> {
  int _selectedIndex = 0;

  static const snackBarDuration = Duration(seconds: 1);

  DateTime backbuttonpressedTime;


  final FirebaseMessaging _firebaseMessaging = FirebaseMessaging();

  final GlobalKey<NavigatorState> homeTabNavKey = GlobalKey<NavigatorState>();
  final GlobalKey<NavigatorState> groupTabNavKey = GlobalKey<NavigatorState>();
  final GlobalKey<NavigatorState> feedTabNavKey = GlobalKey<NavigatorState>();
  final GlobalKey<NavigatorState> userTabNavKey = GlobalKey<NavigatorState>();

  @override
  void initState() {
    _firebaseMessaging.onTokenRefresh.listen(sendTokenToServer);
    _firebaseMessaging.getToken();
  }

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async {
        return !await currentNavigatorKey().currentState.maybePop();
      },
      child: Scaffold(
        body: WillPopScope(
          onWillPop: _onWillPop,
          child: CupertinoTabScaffold(
            tabBar: CupertinoTabBar(
              activeColor: Theme
                  .of(context)
                  .colorScheme
                  .mainColor,
              inactiveColor: Theme
                  .of(context)
                  .colorScheme
                  .greyColor,
              items: [
                BottomNavigationBarItem(
                    icon: Icon(Icons.home)),
                BottomNavigationBarItem(
                    icon: Icon(Icons.group)),
                BottomNavigationBarItem(
                    icon: Icon(Icons.favorite_border)),
                BottomNavigationBarItem(
                    icon: Icon(Icons.account_circle)),
              ],
              onTap: (index) {
                // back home only if not switching tab
                if (_selectedIndex == index) {
                  switch (index) {
                    case 0:
                      homeTabNavKey.currentState.popUntil((r) => r.isFirst);
                      break;
                    case 1:
                      groupTabNavKey.currentState.popUntil((r) => r.isFirst);
                      break;
                    case 2:
                      feedTabNavKey.currentState.popUntil((r) => r.isFirst);
                      break;
                    case 3:
                      userTabNavKey.currentState.popUntil((r) => r.isFirst);
                      break;
                  }
                }
                _selectedIndex = index;
              },
            ),
            tabBuilder: (BuildContext context, int index) {
              switch (index) {
                case 0:
                  return CupertinoTabView(
                    navigatorKey: homeTabNavKey,
                    builder: (BuildContext context) => HomePage(),
                  );
                  break;
                case 1:
                  return CupertinoTabView(
                    navigatorKey: groupTabNavKey,
                    builder: (BuildContext context) => GroupPage(),
                  );
                  break;
                case 2:
                  return CupertinoTabView(
                    navigatorKey: feedTabNavKey,
                    builder: (BuildContext context) => FeedPage(widget.currentUser),
                  );
                  break;
                case 3:
                  return CupertinoTabView(
                    navigatorKey: userTabNavKey,
                    builder: (BuildContext context) =>
                        UserPage(widget.currentUser?.uid),
                  );
                  break;
              }
              return null;
            },
          ),
        ),
      ),
    );
  }

  void sendTokenToServer(String fcmToken) {
    print('Token: $fcmToken');

    Firestore.instance.collection('pushtokens')
        .document(widget.currentUser.uid)
        .setData({
      'pushToken': fcmToken
    });
  }

  GlobalKey<NavigatorState> currentNavigatorKey() {
    switch (_selectedIndex) {
      case 0:
        return homeTabNavKey;
        break;
      case 1:
        return groupTabNavKey;
        break;
      case 2:
        return feedTabNavKey;
        break;
      case 3:
        return userTabNavKey;
        break;
    }

    return null;
  }

//
  Future<bool> _onWillPop() async {
    DateTime currentTime = DateTime.now();
    //Statement 1 Or statement2
    bool backButton = backbuttonpressedTime == null ||
        currentTime.difference(backbuttonpressedTime) > Duration(seconds: 2);
    if (backButton) {
      backbuttonpressedTime = currentTime;
      Fluttertoast.showToast(
          msg: "Double Click to exit app",
          backgroundColor: Colors.black,
          textColor: Colors.white);
      return false;
    }
    return true;
  }
}

Спасибо!

Я наконец решил эту проблему. Выложу обновленный код!

  int backbuttonpressedTime = 0;
  Future<bool> _onWillPop() async {
    var currentTime = DateTime.now().millisecondsSinceEpoch;

    if(!currentNavigatorKey().currentState.canPop()) {
      if (currentTime-backbuttonpressedTime < Duration(seconds: 2).inMilliseconds) {
        return SystemChannels.platform.invokeMethod('SystemNavigator.pop');
      }else{
        Fluttertoast.showToast(
            msg: "Double Click to exit app",
            backgroundColor: Colors.black,
            timeInSecForIos: 1,
            textColor: Colors.white);
        backbuttonpressedTime = currentTime;
        return false;
      }
    }else{
      return true;
    }
  }

Я только модифицировал _onWillPop()часть. Спасибо!

2 ответа

Вот мое решение https://pub.dev/packages/flutter_close_app

      class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return FlutterCloseAppPage(
  onCloseFailed: () {
    // Condition does not match: the first press or the second press interval is more than 2 seconds, display a prompt message
    ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
      content: Text('Press again to exit '),
    ));
  },
  child: Scaffold(
    appBar: AppBar(),
    body: ...
  ),
  );
 }
}

В простых случаях, когда вам нужно перехватить кнопку возврата Android, вы обычно добавляете WillPopScope в дерево виджетов. Однако при разработке виджетов с отслеживанием состояния, которые взаимодействуют с кнопкой "Назад", удобнее использовать BackButtonInterceptor. Взглянуть:

https://pub.dev/packages/back_button_interceptor

Другие вопросы по тегам