플러터 (flutter)

Flutter - 내비게이션 바 (NavigationBar)

CreatoMaestro 2023. 6. 26. 20:46
반응형

저번 글에서는 페이지 간의 연결을 위해 PageView Widget을 이용했다.

이번 글에서는 TabBarView와 BottomNavigationBar 위젯을 이용해 페이지 간의 이동을 구현해 본다.

 

먼저 TabBarView와 BottomNavigationBar에 대해 알아본다.

 

1. TabBarView

TabBarView는 각각의 Tab에 해당하는 화면을 지정해 주는 위젯이다.

여기서 Tab은 일종의 버튼이라고 이해하면 편하다.

TabBar는 여러 개의 tab이 모여있는 위젯이다.

TabBar와 tab, 그리고 TabBarView에 대한 관계를 나타내면 다음과 같다.

TabBarView 구조

Tab이 여러 개 모여있는 위젯을 TabBar라고 하고, 각각의 Tab은 하나의 페이지와 연결이 되어 있다.

TabBarView는 Tab과 연결되어 있는 페이지를 모아 놓은 위젯이다.

때문에 Tab을 선택하면 그에 해당하는 페이지가 나온다.

 

2.BottomNavigationBar

BottomNavigationBar는 TabBar의 일종이다.

아래에 위치하는 내비게이션으로 여러 개의 Tab을 가질 수 있다.

자세한 사용법은 뒤에 가서 설명한다.

 

3. 코드 작성

앞서 말한 것처럼 이번 글에서는 페이지 간 이동을 TabBarView와 BottomNavigationBar를 이용해 구현한다.

단순히 페이지만 넘기는 간단한 코드이다.

 

코드 실행 결과는 다음과 같다.

앱 실행 결과
실행 결과

아래에 있는 NavigatinBar의 tab을 누르면 그에 해당하는 페이지로 넘어간다.

혹은 PageView처럼 슬라이드를 통해 페이지를 넘길 수도 있다.

 

먼저 다음 코드를 넣어준다.

void main() {
  runApp(Root());
}

class Root extends StatefulWidget {
  Root({Key? key}) :super(key: key);

  @override
  State<Root> createState() => _RootState();

}

main 함수에서 Root 클래스가 반환하는 위젯을 실행할 수 있도록 만들어준다.

 

이후 Root를 StatefulWidget으로 만들어준다.

다음으로 Root 함수에 대한 state를 생성해 준다.

 

이 내용은 저번 글에 자세히 나와있다.

2023.06.24 - [단기 프로젝트] - 프로젝트 1_2. Flutter StatefulWidget

 

프로젝트 1_2. Flutter StatefulWidget

이 글에서는 flutter의 statefulwidget에 대해 알아본다. 지금까지는 flutter에 대해 알아보면서 StatelessWidget만을 사용해왔다. StatelessWidget은 상태가 없는 위젯으로 한 번 화면에 띄워지면 다시 바뀌지 않

ti-project-11.tistory.com

 

다음으로는 Root 함수의 State 함수를 생성해 준다.

class _RootState extends State<Root> with TickerProviderStateMixin{

  TabController? tabController;

  @override
  void initState() {
    super.initState();

    tabController = TabController(length: 2, vsync: this);
    tabController!.addListener(tabListener);
  }

  void tabListener() {
    setState(() {

    });
  }

위에서부터 하나하나 살펴보도록 하자.

 

1) 클래스를 선언할 때 평소와 다르게 with TickerProviderStateMixin이 붙어있는 것을 확인할 수 있다.

이는 TickerProviderStateMixin 클래스의 기능을 사용한다는 의미이다.

이 클래스의 기능을 사용해야 페이지가 넘어가는 애니메이션을 넣을 수 있다.

 

2) TabController? tabController는 TabBarView에서 사용할 컨트롤러이다.

이 컨트롤러가 있어야 우리가 원하는 대로 동작을 시킬 수 있다.

 

3) void initState()는 state를 초기화시키는 역할을 한다.

우선 부모 클래스(StatefulWidget)의 initState()를 실행한다.

이후 TabController() 생성자를 이용해 컨트롤러를 생성해 준다.

뒤에 붙는 length는 페이지의 수를 의미하고, vsync는 에니매이션을 위해 필요하다.

 

4) 컨트롤러에 addListener를 추가해 준다.

뒤에 붙는 파라미터는 함수이다.

이를 통해 tab이 터치되었을 때 어떤 함수를 실행할지 알 수 있다.

만약 필요하다면 tabListener의 setState 안에 원하는 기능을 넣어줄 수 있다.

 

@override
void dispose() {
  tabController!.removeListener(tabListener);
  super.dispose();
}

다음은 dispose 메서드이다. 

dispose 메서드는 위젯의 주기가 끝났을 때 행해지는 메서드이다.

화면이 넘어가면 위젯의 주기가 끝나기 때문에 dispose가 실행이 되게 된다.

주기가 끝날 때 listener를 없애주어야 하기 때문에 removeListener를 통해 listener를 없애준다.

 

List<Widget> tabWidget() {
  return [
    Container(
      child: Center(
        child: Text("page1"),
      ),
    ),
    Container(
      child: Center(
        child: Text("page2"),
      ),
    ),
  ];
}

위 코드는 tabBarView의 children 파라미터에 들어갈 위젯을 반환해 준다.

2개의 컨테이너를 list로 묶어 반환해 준다. 

쓰인 순서대로 페이지가 결정이 된다.

Container는 위젯을 담는 역할을 하는 위젯이다.

 

List<BottomNavigationBarItem> NaviItems() {
  return const[
    BottomNavigationBarItem(
        icon: Icon(
          Icons.calculate_outlined,
        ),
      label: "Page1",
    ),
    BottomNavigationBarItem(
      icon: Icon(
        Icons.settings,
      ),
      label: "Page2",
    ),
  ];
}

위 코드는 BottomNavigationBar의 items 파라미터에 들어갈 item들을 반환해준다.

전에 봤던 코드와 마찬가지로 list로 묶어서 반환해준다.

icon은 Tab에서 보여줄 아이콘을 의미하고, label은 그 밑에 있는 라벨을 의미한다.

 

@override
Widget build(BuildContext context) {
  return MaterialApp(
    theme: ThemeData.dark(),
    home: Scaffold(
      body: TabBarView(
        controller: tabController,
        children: tabWidget(),
      ),
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: tabController!.index,
        onTap: (int index) {
          tabController!.animateTo(index);
        },
        items: NaviItems(),
      ),
    ),
  );
}

다음은 build 메서드이다.

Scaffold까지는 이전에 설명했던 것과 똑같다.

theme의 경우 MaterialApp에서 사용할 테마를 의미한다.

여기서는 dark테마를 사용하였다.

 

Scaffold의 body로는 TabBarView가 들어갔다. 

controller는 위에서 생성해 준 tabController를 넣어주고, childrne으로는 widget list를 반환해 주는 tabWidget()을 호출하였다.

이렇게 하면 children에 반환한 리스트가 들어가게 된다.

 

bottomNabigationBar에는 BottomNavigationBar 위젯을 넣어준다.

currentIndex는 현재 컨트롤러가 가리키고 있는 index를 넣어준다. 

이를 통해 tabBarView의 index와 동일한 index를 맞춰줄 수 있다.

 

onTap은 내비게이션이 눌렸을 때 어떤 동작을 할지 결정해 주는 위젯이다.

우리는 눌렸을 때 페이지가 넘어가길 바라기 때문에 tabController를 이용해 페이지를 넘겨준다.

 

items는 내비게이션에 들어갈 tab을 결정한다.

여기서는 앞서 생성한 NaviItems() 함수를 호출해 준다.

여기서 반환된 리스트를 값으로 받게 된다.

 

아래는 전체 코드이다.

import 'package:flutter/material.dart';

void main() {
  runApp(Root());
}

class Root extends StatefulWidget {
  Root({Key? key}) :super(key: key);

  @override
  State<Root> createState() => _RootState();

}

class _RootState extends State<Root> with TickerProviderStateMixin{

  TabController? tabController;

  @override
  void initState() {
    super.initState();

    tabController = TabController(length: 2, vsync: this);
    tabController!.addListener(tabListener);
  }

  void tabListener() {
    setState(() {

    });
  }

  @override
  void dispose() {
    tabController!.removeListener(tabListener);
    super.dispose();
  }

  List<Widget> tabWidget() {
    return [
      Container(
        child: Center(
          child: Text("page1"),
        ),
      ),
      Container(
        child: Center(
          child: Text("page2"),
        ),
      ),
    ];
  }

  List<BottomNavigationBarItem> NaviItems() {
    return const[
      BottomNavigationBarItem(
          icon: Icon(
            Icons.calculate_outlined,
          ),
        label: "Page1",
      ),
      BottomNavigationBarItem(
        icon: Icon(
          Icons.settings,
        ),
        label: "Page2",
      ),
    ];
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark(),
      home: Scaffold(
        body: TabBarView(
          controller: tabController,
          children: tabWidget(),
        ),
        bottomNavigationBar: BottomNavigationBar(
          currentIndex: tabController!.index,
          onTap: (int index) {
            tabController!.animateTo(index);
          },
          items: NaviItems(),
        ),
      ),
    );
  }

}




 

이로써 abBarView와 BottomNavigationBar 위젯을 이용한 페이지 이동을 구현완료 하였다.

반응형