앱 페이지 구성중 하단에 버튼들을 고정시켜놓고 사용하는 경우가 있다.
고정된 버튼을 클릭하면 각각 설정된 페이지로 이동한다.
Flutter에서도 해당 기능을 지원한다.
초반에 배우는 Scaffold Widget 내부 속성에 있는 BottomNavigationBar 가 그 주인공이다.
우선 Scaffold 내부에 bottomNavigationBar를 선언한다.
items 속성이 required. 즉 필수로 들어가야 한다.
Scaffold(
bottomNavigationBar: BottomNavigationBar(
items: const [],
);
items는 하단 NavigationBar에 들어갈 버튼들이 들어가게 된다.
아무 위젯이나 넣을수는 없고, BottomNavigationBarItem을 넣어줘야 한다.
기본적인 활용 방식은 아래와 같다.
BottomNavigationBarItem(
icon: Icon(Icons.contact_page,),
label: "버튼 이름"),
BottomNavigationBarItem 을 선언하고, 아이콘의 모양과 설명글을 적어주는 방식이다.
label은 생략 가능하다.
이런식으로 아이템들을 추가해주면 아래처럼 설정이 가능하다.
추가로 넣은 backgroundColor와 fixedColor는 각각 배경색, 클릭시 글자/아이콘색을 의미한다.
Scaffold(
bottomNavigationBar: BottomNavigationBar(
currentIndex: _selectedIndex,
onTap: _onItemTapped,
items: const [
BottomNavigationBarItem(
icon: Icon(
Icons.contact_page,
),
label: "첫번째 버튼"),
BottomNavigationBarItem(
icon: Icon(
Icons.abc_rounded,
),
label: "두번째 버튼"),
BottomNavigationBarItem(
icon: Icon(
Icons.ac_unit_rounded,
),
label: "세번째 버튼"),
],
backgroundColor: mainColor,
fixedColor: Colors.white,
),
),
이제 네비게이션 버튼들은 생성되었으니 각 버튼을 눌렀을 때 이동할 페이지를 만들어보자.
나는 간단하게 아래와 같이 페이지를 만들고 배열에 담았다.
지금 생각해보니 한개만 만들고 변수를 받아서 넣으면 되는데 굳이 3개를 일일히 적은 나 자신을 반성한다.
List test = <Widget>[firstScreenTest(), secondScreenTest(), thirdScreenTest()];
class firstScreenTest extends StatelessWidget {
const firstScreenTest({super.key});
@override
Widget build(BuildContext context) {
return Text("첫번째 화면");
}
}
class secondScreenTest extends StatelessWidget {
const secondScreenTest({super.key});
@override
Widget build(BuildContext context) {
return Text("두번째 화면");
}
}
class thirdScreenTest extends StatelessWidget {
const thirdScreenTest({super.key});
@override
Widget build(BuildContext context) {
return Text("세번째 화면");
}
}
어쨌든 화면은 선언되었고, 이제 우리는 버튼을 눌렀을 때 각 페이지를 볼 수 있도록 설정해야 한다.
_selectedIndex는 어떤 페이지가 선택되었는지 살펴볼 수 있게 하는 int 형의 변수로 선언했다.
그리고 Scoffold 위젯의 body에 우리가 선언한 배열의 값을 담는다.
int _selectedIndex = 0; //추가한 변수
@override
Widget build(BuildContext context) {
....생략....
Scaffold(
body: test.elementAt(_selectedIndex),
bottomNavigationBar: BottomNavigationBar(..생략
마지막으로 버튼을 누르면 각각의 페이지로 이동할 수 있도록 선언한다.
int _selectedIndex = 0;
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index; // 페이지/네비게이션 바 활성화 값 적용
});
}
@override
Widget build(BuildContext context) {
....생략....
bottomNavigationBar: BottomNavigationBar(
currentIndex: _selectedIndex, //현재 네비게이션 바 활성화된 인덱스
onTap: _onItemTapped, //클릭시 클릭한 index값을 전달
items: const [...생략....
충격적이게도 해당 Widget은 3개 이상의 BottomNavigationBarItem을 넣으면 배경이 하얘지는 현상이 발생했다.
알아보니 기본적으로 bottomNavigationBar의 type 속성이 shifting 으로 설정되어 있는데, 이 속성이 3개 이상은 적용되지 않는다고 한다.
그래서 fix로 고치면 해결 가능하다.
아래 속성을 bottomNavigationBar 내부에 집어넣자.
type: BottomNavigationBarType.fixed,
그럼 버그 해결 완료된다.
끝났다.
전체 소스 보고 마무리하자.
List test = <Widget>[firstScreenTest(), secondScreenTest(), thirdScreenTest()];
class Example extends StatefulWidget {
const Example({super.key});
@override
State<Example> createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
int _selectedIndex = 0;
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
@override
Widget build(BuildContext context) {
bool backButtonChk = false; //뒤로가기 클릭여부 파악
///뒤로가기 클릭시 Splash 화면으로 넘어가는것을 방지
///더불어 2초 안에 2번 뒤로가기를 누르면 앱 종료 기능 추가
return Scaffold(
body: test.elementAt(_selectedIndex),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _selectedIndex,
onTap: _onItemTapped,
items: const [
BottomNavigationBarItem(
icon: Icon(
Icons.contact_page,
),
label: "첫번째 버튼"),
BottomNavigationBarItem(
icon: Icon(
Icons.abc_rounded,
),
label: "두번째 버튼"),
BottomNavigationBarItem(
icon: Icon(
Icons.ac_unit_rounded,
),
label: "세번째 버튼"),
],
backgroundColor: mainColor,
fixedColor: Colors.white,
),
);
}
}
class firstScreenTest extends StatelessWidget {
const firstScreenTest({super.key});
@override
Widget build(BuildContext context) {
return Text("첫번째 화면");
}
}
class secondScreenTest extends StatelessWidget {
const secondScreenTest({super.key});
@override
Widget build(BuildContext context) {
return Text("두번째 화면");
}
}
class thirdScreenTest extends StatelessWidget {
const thirdScreenTest({super.key});
@override
Widget build(BuildContext context) {
return Text("세번째 화면");
}
}