내가 바텀네비게이션을 직접 구현하게 된 이유는
- 플러터에서 기본적으로 제공하는 BottomNavigationBar가 있는데 너무 구려서 못써먹겠다.
- 디자이너가 요구하는 디자인에 다 맞춰보니 자꾸 layout overflow가 생기는데 이럴거면 그냥 직접 만드는게 낫겠다 싶다.
한번 만들어 보니 그 방법은 의외로 간단했다. 그래서 어거지고 기본 네비게이션을 쓰려고 한 내 시간이 너무 아까웠다.
Scaffold(
body: Stack(
children: [
IndexedStack(
index: _selectedIndex,
children: [
Bookmarkscreen(),
Mapscreen(),
Menuscreen(),
],
),
Positioned(
left: screenWidth * 0.1,
right: screenWidth * 0.1,
bottom: MediaQuery.of(context).size.height * 0.055,
child: bottomNavigation(screenSize),
),
],
),
);
IndexedStack을 사용하여 페이지를 렌더링 한다.
디자이너가 화면 하단에서 살짝띄운 네비게이션을 원해서 Scaffold body 위에 Stack위젯으로 화면과 네비를 동시에 띄웠다.
Widget bottomNavigation(Size screensize) {
return Container(
width: screensize.width * 300 / 375,
height: screensize.height * 80 / 812,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/navigation.png')
),
),
child: Row(
children: [
GestureDetector(
child: Container(
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 22),
width: 100,
height: 80,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SvgPicture.asset(
_selectedIndex == 0
? 'assets/images/btn_plug.svg'
: 'assets/images/ic_star.svg',
width: _selectedIndex == 0 ? 56 : 28,
height: _selectedIndex == 0 ? 56 : 28,
),
Visibility(
visible: _selectedIndex == 0 ? false : true,
child: Text(
'저장',
style: B5_KR_Rg_12.copyWith(color: gray_300),
textAlign: TextAlign.center,
),
)
],
),
),
onTap: () {
_onItemTapped(0);
},
),
GestureDetector(
child: Container(
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 22),
width: 100,
height: 80,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SvgPicture.asset(
_selectedIndex == 1 ? 'assets/images/btn_home.svg': 'assets/images/ic_plug.svg',
width: _selectedIndex == 1 ? 56 : 28,
height: _selectedIndex == 1 ? 56 : 28),
Visibility(
visible: _selectedIndex == 1 ? false : true,
child: Text(
'홈',
style: B5_KR_Rg_12.copyWith(color: gray_300),
textAlign: TextAlign.center,
),
)
],
),
),
onTap: () {
_onItemTapped(1);
},
),
GestureDetector(
child: Container(
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 22),
width: 100,
height: 80,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SvgPicture.asset(
_selectedIndex == 2 ? 'assets/images/btn_menu.svg': 'assets/images/ic_menu.svg',
width: _selectedIndex == 2 ? 56 : 28,
height: _selectedIndex == 2 ? 56 : 28),
Visibility(
visible: _selectedIndex == 2 ? false : true,
child: Text(
'메뉴',
style: B5_KR_Rg_12.copyWith(color: gray_300),
textAlign: TextAlign.center,
),
)
],
),
),
onTap: () {
_onItemTapped(2);
},
)
],
),
);
}
코드가 길긴하지만 별거 없고 onTab에서
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
선택한 화면 index를 넘겨주는 메서드를 만들어서 사용해주었다.
SvgPicture.asset(
_selectedIndex == 0
? 'assets/images/btn_plug.svg'
: 'assets/images/ic_star.svg',
width: _selectedIndex == 0 ? 56 : 28,
height: _selectedIndex == 0 ? 56 : 28,
),
Visibility(
visible: _selectedIndex == 0 ? false : true,
child: Text(
'저장',
style: B5_KR_Rg_12.copyWith(color: gray_300),
textAlign: TextAlign.center,
),
)
또한 선택시에 1. 밑에 title이 없어짐, 2. 이미지가 바뀜, 3. 이미지가 커짐을 구현했다.
앞으로 디자인이 빡세면 기본을 쓰는거보다 직접구현하는 게 학습적으로도 좋아보인다.
'[Flutter]' 카테고리의 다른 글
플러터 ios 배포 - 버전 변경 (0) | 2024.12.23 |
---|---|
Flutter 실내지도를 구현하기 까지의 여정(2) (5) | 2024.11.09 |
Flutter 실내지도를 구현하기 까지의 여정(1) (2) | 2024.08.19 |
Flutter Textfield 정리 (2) | 2024.07.31 |
Flutter Row, Column 정렬 (4) | 2024.07.31 |