제철음식 알리미 앱을 제작하며 학습했던 내용들을 정리한다.
1. BottomNavBar
bottomNavBar 요소를 통해서 페이지를 이동할 수 있도록 했다. Scaffold 내부에 bottomNavigationBar 인자로 아래와 같이 BottomNavBar를 추가했다.
bottomNavigationBar: BottomNavBar(
selectedIndex: _selectedIndex,
onItemTapped: _onItemTapped,
)
여기서 _selectedIndex, _onItemTapped를 통해 현재 선택된 index 값과 홈 또는 검색 아이콘이 클릭되었을 때의 행동을 정의한다. selectedIndex 값은 홈페이지의 index 값을 0, 검색 페이지의 index 값을 1로 두었다. 그리고 onItemTapped에서 변경이 감지되도록 하고 조건에 따라 어떤 페이지로 이동하고 값을 관리할지 결정한다.
Navigator.canPop을 통해 현재 Navigator 스택에 페이지가 남아있는지 검사하는 부분은 스택에 이미 페이지가 쌓여있는 경우 페이지를 더 쌓지 않고 현재 페이지를 다른 페이지로 전환하도록 하기 위함이다. 스택에 페이지가 계속 쌓이면 사용자가 뒤로가기를 계속 해야하는 불편함이 생길 수 있다.
pushReplacementNamed, pushNamed에 대해서는 아래 글에서 정리한 바가 있다.
https://whitepro.tistory.com/1019
class _HomeViewState extends State<HomeView> {
// ...생략
final PageController _pageController = PageController();
int _selectedIndex = 0;
// ... 중략
void _onItemTapped(int index) {
if (index == _selectedIndex) {
return;
}
setState(() {
_selectedIndex = index;
});
if (Navigator.canPop(context)) {
if (index == 0) {
Navigator.pushReplacementNamed(context, '/home',
arguments: {'selectedIndex': 0});
} else if (index == 1) {
Navigator.pushReplacementNamed(context, '/search',
arguments: {'selectedIndex': 1});
}
} else {
if (index == 0) {
Navigator.pushNamed(context, '/home', arguments: {'selectedIndex': 0});
} else if (index == 1) {
Navigator.pushNamed(context, '/search',
arguments: {'selectedIndex': 1});
}
}
}
}
이렇게 BottomNavBar 및 _selectedIndex, _onItemTapped를 정의하는 부분은 위에서 다룬 홈페이지 뿐만 아니라 상세 페이지 등 네비게이션이 필요하고 그 상태가 유지되어야하는 모든 페이지에 똑같이 추가해주었다. 중복 코드가 발생하기 때문에 공통화하고 싶었는데, 방법을 찾지 못했고, 페이지가 많지 않아서 일단은 그대로 적용했었다.
검색화면도 마찬가지다.
예를 들어 검색화면의 코드에도 아래와 같이 코드가 작성되어있다.
class SearchFoodView extends StatefulWidget {
@override
_SearchFoodViewState createState() => _SearchFoodViewState();
}
class _SearchFoodViewState extends State<SearchFoodView> {
//...생략
int _selectedIndex = 0;
//...생략
void _onItemTapped(int index) {
if (index == _selectedIndex) {
return;
}
setState(() {
_selectedIndex = index;
});
if (index == 0) {
Navigator.pushNamedAndRemoveUntil(context, '/home', (route) => false, arguments: {'selectedIndex': 0});
} else if (index == 1) {
Navigator.pushReplacementNamed(context, '/search', arguments: {'selectedIndex': 1});
}
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
final arguments = ModalRoute.of(context)?.settings.arguments as Map?;
if (arguments != null && arguments.containsKey('selectedIndex')) {
setState(() {
_selectedIndex = arguments['selectedIndex'];
});
}
}
@override
Widget build(BuildContext context) {
return GestureDetector(
//...중략
bottomNavigationBar: BottomNavBar(
selectedIndex: _selectedIndex,
onItemTapped: _onItemTapped,
)),
);
}
}
'Programming-[CrossPlatform] > Flutter' 카테고리의 다른 글
Flutter Provider: 2. ChangeNotifierProvider, MultiProvider (1) | 2025.01.02 |
---|---|
Flutter Provider: 1. Provider와 State management (0) | 2025.01.01 |
[제철음식 알리미] ValueListenableBuilder, ValueNotifier (0) | 2024.10.21 |
[제철음식 알리미] 2. 화면 요소: Flexible, Expanded, Positioned (1) | 2024.10.20 |
[제철음식 알리미] 1. 화면구성: Stack, Navigator, PageView (0) | 2024.10.14 |