[Flutter / 플러터] 내비게이션 바, 탭 바 사용하기 (Tab Bar)

반응형

탭 바, 일반적으로 내비게이션 바라고 부르는 뷰를 만들어보자

 

많이 쓰이는 것들은 BottomNavigationBar, TabBar, PageView 등등

내비게이션 바, 페이지를 만드는데 사용할 수 있는 위젯은 다양하다.

이 중 TabBar를 사용해보자

 

보통 내비게이션 바에는 4개의 탭이 있고, 상단 또는 하단에 위치하게 된다.

 

4개의 탭을 생성해보자

 

TabBar(
    indicatorColor: Colors.yellow, // 선택 영역 색깔
    indicatorSize: TabBarIndicatorSize.tab, // 선택 영역 색 범위 탭 영역 전체 (길다란 선)
    controller: _tabController, // 탭 컨트롤러
    tabs: [
      IgnorePointer(
        child: IconButton(
          onPressed: () {},
          icon: const Icon(Icons.home_filled),
        ),
      ),
      IgnorePointer(
        child: IconButton(
          onPressed: () {},
          icon: const Icon(Icons.add_box_outlined),
        ),
      ),
      IgnorePointer(
        child: IconButton(
          onPressed: () {},
          icon: const Icon(Icons.list_alt),
        ),
      ),
      IgnorePointer(
        child: IconButton(
          onPressed: () {},
          icon: const Icon(Icons.person),
        ),
      ),
    ],
),

 

IconButton은 아이콘에 버튼 기능이 추가된 위젯이다.

아이콘을 버튼으로 사용하기 위함.

그런데 왜 IgnorePointer를 위로 감싸주었을까?

 

TabBar 에 넣어주는 tab들은 기본적으로 버튼 기능을 하는데 (탭을 누르면 이동해야하니까)

IconButton은 자기만의 버튼 영역이 있어서 IconButton 만을 누를 경우 탭 이동은 되지 않는다.

 

이렇게 눌리면 탭이 이동되지만

 

이렇게 눌리면 이동이 되지 않는다

 

이제 탭 버튼을 만들었으니 탭 이동시 같이 이동하는 페이지를 만들어보자

 

필자는 탭바를 상단에 뒀기 때문에 TabBarView 를 그 밑에 위치시켰다.

Expanded(
  child: TabBarView(
    controller: _tabController,
    children: const [
      Center(
        child: Text('홈 화면'),
      ),
      Center(
        child: Text('추가 화면'),
      ),
      Center(
        child: Text('리스트 화면'),
      ),
      Center(
        child: Text('마이페이지'),
      ),
    ],
  ),
),

 

Expanded 로 TabBarView 를 감싸주지 않으면 에러가 발생하니 참고할 것

 

 

여기도 controller를 넣어줬는데 대체 얜 뭘까?

말그대로 탭을 다루게 해주는 controller 

TabBar, TabBarView 가 나눠져있는데, 둘에게 동일한 controller 를 부여하여 동기화되어 동작할 수 있도록 하기 위함이다

 

class _HomePageState extends State<MyHomePage> with TickerProviderStateMixin {
  late TabController _tabController;

  @override
  void initState() {
    _tabController = TabController(length: 4, vsync: this);
    super.initState();
  }

 

with TickerProviderStateMixin 을 추가하고

TabController 에 vsync: this 를 추가해줘야 한다

 

with 의 개념은 어려울 수 있으니 다른 글을 참고하는걸 추천

간단히 설명하면 탭 바가 이동될 때 애니메이션이 들어가게 되는데 이 애니메이션을 다룰 수 있도록 도와주는 녀석이라고 보면 된다.

 

이게 어려우면 단순하게 적용하는 방법도 있다.

DefaultTabController 를 이용하는 방법이다.

body: DefaultTabController(
  length: 4,
  child: Center(
    child: Column(
      children: [
        TabBar(
            indicatorColor: Colors.yellow,
            indicatorSize: TabBarIndicatorSize.tab,
            tabs: [

 

DefaultTabController로 둘 모두를 감싸고, controller를 따로 부여하던걸 없애주면 된다.

 

 

어쨋든 이를 모두 적용하면 다음과 같이 나타난다

 

 

적용 영상

 

 

 

full code

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: DefaultTabController(
        length: 4,
        child: Center(
          child: Column(
            children: [
              TabBar(
                  indicatorColor: Colors.yellow,
                  indicatorSize: TabBarIndicatorSize.tab,
                  tabs: [
                    IgnorePointer(
                      child: IconButton(
                        onPressed: () {},
                        icon: const Icon(Icons.home_filled),
                      ),
                    ),
                    IgnorePointer(
                      child: IconButton(
                        onPressed: () {},
                        icon: const Icon(Icons.add_box_outlined),
                      ),
                    ),
                    // IgnorePointer(
                    //   child:
                    IconButton(
                      onPressed: () {},
                      icon: const Icon(Icons.list_alt),
                    ),
                    // ),
                    IgnorePointer(
                      child: IconButton(
                        onPressed: () {},
                        icon: const Icon(Icons.person),
                      ),
                    ),
                  ]),
              const Expanded(
                child: TabBarView(
                  children: [
                    Center(
                      child: Text('홈 화면'),
                    ),
                    Center(
                      child: Text('추가 화면'),
                    ),
                    Center(
                      child: Text('리스트 화면'),
                    ),
                    Center(
                      child: Text('마이페이지'),
                    ),
                  ],
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

 

 

반응형