앱 실행 중에 마지막 스택에서 뒤로 가기 버튼을 누르면 "뒤로 가기를 한 번 더 누르시면 종료됩니다"라는 내용의 스낵바가 뜨는 기능을 구현해 보자.
PopSope 위젯 추가하기
DateTime? backPressedTime;
@override
Widget build(BuildContext context) {
return PopScope(
canPop: false,
onPopInvoked: (bool didPop) {
if (didPop) {
return;
}
DateTime nowTime = DateTime.now();
if (backPressedTime == null ||
nowTime.difference(backPressedTime!) > const Duration(seconds: 2)) {
backPressedTime = nowTime;
showSnackbar('한 번 더 누르시면 종료됩니다.');
} else {
SystemNavigator.pop(); // 앱 종료
}
},
child: const Scaffold(),
);
}
- `Scaffold` 위젯을 `PopScope`로 감싼다.
- `onPopInvoked`에 뒤로 가기 이벤트가 감지될 때 실행할 코드를 작성한다.
- 처음 뒤로 가기를 했을 때는 스낵바를 띄우고, 설정한 시간 안에 한 번 더 뒤로 가기를 눌렀을 때 앱이 종료되도록 했다.
PageView 사용 시 주의할 점
- 처음에는 각각의 탭에 `PopScope` 위젯을 추가했다.
- 그런데 타임라인 탭에서 뒤로 가기를 누르면 홈 탭과 타임라인 탭의 `onPopInvoked`가 동시에 실행되는 문제가 발생했다. 이로 인해 `onPopInvoked`가 두 번 실행되면서 무조건 앱이 종료되었다.
- 문제의 원인은 `PageView`가 모든 탭을 활성화 상태로 유지하면서 모든 탭의 `onPopInvoked`가 중첩되어 실행되는 것이었다.
@override
Widget build(BuildContext context) {
return PopScope(
canPop: false,
onPopInvoked: (bool didPop) {
// 제외하고 싶은 탭이 있는 경우 if문 추가
if (_currentIndex != 2) {
DateTime nowTime = DateTime.now();
if (backPressedTime == null ||
nowTime.difference(backPressedTime!) > const Duration(seconds: 2)) {
backPressedTime = nowTime;
showSnackbar('한 번 더 누르시면 종료됩니다.');
} else {
SystemNavigator.pop(); // 앱 종료
}
}
},
child: Scaffold(
body: PageView(
physics: const NeverScrollableScrollPhysics(),
controller: _pageController,
onPageChanged: _onItemTapped,
children: _tabs,
),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
currentIndex: _currentIndex,
onTap: _onItemTapped,
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: '홈',
),
BottomNavigationBarItem(
icon: Icon(Icons.list),
label: '타임라인',
),
BottomNavigationBarItem(
icon: Icon(Icons.image_outlined),
label: '앨범',
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: 'MY',
),
],
),
),
);
}
- 문제를 해결하기 위해서 각 탭에 추가했던 `PopScope` 위젯을 지우고, `PageView`가 포함된 `Scaffold` 위젯 하나에만 `PopScope`를 사용했다.