我是扑朔迷离的新手,我看到双击后退按钮时,许多android应用程序都可以退出。
第一次按下后退按钮,应用程序显示吐司“再次按下以退出应用程序”。 在第二次按下时,应用程序退出。 当然,两次按下之间的时间不能太长。
如何扑通扑通?
答案 0 :(得分:15)
这是我的代码示例(我用“ fluttertoast”作为昭通吐司-您可以使用小吃店或警报器或其他工具)
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);
}
答案 1 :(得分:2)
这是我的答案。我使用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;
}
答案 2 :(得分:2)
不幸的是,它们都不适合我,我编写了一个通用类(小部件)来处理双击退出。如果有人感兴趣
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'),
],
),
),
),
),
);
}
}
答案 3 :(得分:1)
只需使用double_back_to_close_app库
https://pub.dev/packages/double_back_to_close_app
在pubspec.yaml文件中的依赖项下添加double_back_to_close_app
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的”孩子
答案 4 :(得分:1)
如果您需要小吃车,则应提供与脚手架相关的脚手架钥匙,因此此钥匙应具有在其脚手架父级之外调用小吃车的技巧。
这是一个解决方案:
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")
);
)
}
答案 5 :(得分:1)
这是我的解决方案,您可以将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);
}
}
答案 6 :(得分:1)
如果条件是用户仅按两次,则当然可以使用第一种解决方案。 如果要增加单击次数,可以使用此解决方案。用户必须在两秒钟内按下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);
}
答案 7 :(得分:0)
您也可以选择加入涉及SnackBar
的解决方案。它不像Andrey Turkovsky的答案那么简单,但是却更加优雅,您不必依赖库。
使用Key
:
class _FooState extends State<Foo> {
static const snackBarDuration = Duration(seconds: 3);
final snackBar = SnackBar(
content: Text('Press back again to leave'),
duration: snackBarDuration,
);
final scaffoldKey = GlobalKey<ScaffoldState>();
DateTime backButtonPressTime;
@override
Widget build(_) {
return Scaffold(
key: scaffoldKey,
body: WillPopScope(
onWillPop: onWillPop,
child: Text('Place your child here'),
),
);
}
Future<bool> onWillPop() async {
DateTime currentTime = DateTime.now();
bool backButtonHasNotBeenPressedOrSnackBarHasBeenClosed =
backButtonPressTime == null ||
currentTime.difference(backButtonPressTime) > snackBarDuration;
if (backButtonHasNotBeenPressedOrSnackBarHasBeenClosed) {
backButtonPressTime = currentTime;
scaffoldKey.currentState.showSnackBar(snackBar);
return false;
}
return true;
}
}
没有Key
:
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(_) {
return Scaffold(
body: Builder(
builder: (BuildContext context) {
// The BuildContext must be from one of the Scaffold's children.
return WillPopScope(
onWillPop: () => onWillPop(context),
child: Text('Place your child here'),
);
},
),
);
}
Future<bool> onWillPop(BuildContext context) async {
DateTime currentTime = DateTime.now();
bool backButtonHasNotBeenPressedOrSnackBarHasBeenClosed =
backButtonPressTime == null ||
currentTime.difference(backButtonPressTime) > snackBarDuration;
if (backButtonHasNotBeenPressedOrSnackBarHasBeenClosed) {
backButtonPressTime = currentTime;
Scaffold.of(context).showSnackBar(snackBar);
return false;
}
return true;
}
}
答案 8 :(得分:0)
第一次按下后退按钮,应用程序将显示一个AlertDialog“按yes退出应用程序,然后按No退出应用程序”。 这是我的代码示例(我使用了“ 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;
}