【问题标题】:Flutter back button颤动返回按钮
【发布时间】:2026-01-17 20:55:01
【问题描述】:

我在主屏幕中添加了以下代码,以便在点击 2 次后退按钮后退出应用程序

Widget build(BuildContext context) {
  return WillPopScope(
    onWillPop: () async {
      final timeGap = DateTime.now().difference(preBackpress);
      final cantExit = timeGap >= const Duration(seconds: 2);
      preBackpress = DateTime.now();
      if(cantExit){
        const snack = SnackBar(
          content: Text('Press Back button again to Exit'),
          duration: Duration(seconds: 2),
        );
        ScaffoldMessenger.of(context).showSnackBar(snack);
        return false;
      }else{
        return true;
      }
    },
    child: Scaffold(....)
  );
}

但我得到的是,当我点击返回按钮时,它会返回所有步骤,以返回每个已访问过的单个屏幕用户。

我在上面添加WillPopScope 的原因是为了避免返回访问过的屏幕并关闭应用程序,但它似乎仍然没有帮助。

我的问题是:如何退出应用程序(在主屏幕中点击返回按钮时)而不返回访问过的屏幕?

【问题讨论】:

标签: flutter dart


【解决方案1】:

也许这与您的代码不同。但我有代码可以根据需要关闭应用程序

class ExitController extends StatefulWidget {
  @override
  _ExitControllerState createState() => _ExitControllerState();
}

class _ExitControllerState extends State<ExitController> {
  static const snackBarDuration = Duration(milliseconds: 2000);
  // set how long the snackbar appears
  final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
  DateTime? backButtonPressTime;

  final snackBar = SnackBar(
    behavior: SnackBarBehavior.floating,
    // margin: EdgeInsets.fromLTRB(75, 0, 75, 250),
    // add margin so that the snackbar is not at the bottom
    duration: snackBarDuration,
    backgroundColor: Colors.black87,
    content: Text('Press Again to Exit',
        textAlign: TextAlign.center,
        style: TextStyle(fontWeight: FontWeight.bold, fontSize: 12)),
  );

  Future<bool> onWillPop() async {
    DateTime currentTime = DateTime.now();

    bool backButtonCondition =
        backButtonPressTime == null ||
            currentTime.difference(backButtonPressTime!) > snackBarDuration;

    if (backButtonCondition) {
      backButtonPressTime = currentTime;
      ScaffoldMessenger.of(context).showSnackBar(snackBar);
      return false;
    }
    return true;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: scaffoldKey,
      body: WillPopScope(
        onWillPop: onWillPop,
        child: yourPageClass(),
      ),
    );
  }
}

snackbar 将显示 2000 毫秒,在此期间如果用户再次按下返回按钮,应用程序将退出

注意在 main.dart 中调用 ExitController 类,并用这个 ExitController 类包装你的所有结构(导航类/页面类/等)。 示例:

main.dart

import 'package:flutter/material.dart';
import 'package:app_name/structure.dart';

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

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

【讨论】:

  • 它仍然做同样的事情(转到前一个屏幕),唯一的区别是它需要 2 次后退按钮来显示前一个屏幕! ://
  • 你把 WillPopScope 放在哪里了?您是否将 WillPopScope 作为父类和所有类?
  • 是的,与您的示例代码结构相同
  • 你的问题是说当用户从第一页移动到第二页时,即使在第二页,用户也可以关闭应用程序?
  • 我确信由于您创建的类结构或包装类结构的方式而出现此问题。不是因为你附加的代码。
【解决方案2】:
WillPopScope(
        onWillPop: () async {
          return await showDialog(context: ctx, builder: (_) => exitAlertDialog(_));
        },
        child: GestureDetector(onTap: () => FocusScope.of(ctx).unfocus(), child: widget));

Widget exitAlertDialog(BuildContext context) {
  return AlertDialog(
    backgroundColor: plColor2,
    content: Text('Are you sure you want to exit?'),
    actions: <Widget>[
      TextButton(child: Text('No'), onPressed: () => Navigator.of(context).pop(false)),
      TextButton(child: Text('Yes, exit'), onPressed: () => SystemNavigator.pop())
    ],
  );
}

或者你可以根据需要使用showsnackbar

【讨论】:

  • 显示小吃店不是我的问题,请阅读问题