IT/Flutter

[Flutter] 하단 탭바 만들기 (BottomNavigationBar, SingleTickerProviderStateMixin)

안경 쓴 귀니 2025. 10. 10. 00:43
반응형

Flutter 하단 탭바 만드는 방법

 

요즘 대부분 많은 앱에서 하단 탭바를 사용하고 있습니다.

대표적으로 카카오톡, 인스타그램, 유튜브 등이 있죠.

여러 화면에 접근하기 쉬워서 많이 사용하는 것 같아요.

 

하단 탭바 만드는 방법은 생각보다 간단해요.

 

1. SingleTickerProviderStateMixin 사용

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen>
    with SingleTickerProviderStateMixin { }

 

 

2. TabController _tabController, int _selectedIndex 변수 선언

late TabController _tabController;
int _selectedIndex = 0;

_selectIndex는 사용자가 선택한 탭 인덱스 번호입니다.

 

 

3. initState()와 tabController 초기화 및 리스너 추가, dispose() 에서 컨트롤러 해제

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: 3, vsync: this);
    _tabController.addListener(
          () => setState(() => _selectedIndex = _tabController.index),
    );
  }

  @override
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }

TabController 개수를 3으로 설정해주고,

addListener를 사용해서 탭 바가 클릭될 경우 _selectedIndex 값을 변경하도록 setState() 해줍니다.

 

 

4. build()에서 bottomNavigationBar 위젯 배치

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text("Title"), backgroundColor: Colors.white),
        bottomNavigationBar: SizedBox(
          height: 70,
          child: TabBar(
            indicatorColor: Colors.red,
            labelColor: Colors.black,
            controller: _tabController,
            tabs: <Widget>[
              Tab(icon: Icon(Icons.schedule), text: "스케줄"),
              Tab(icon: Icon(Icons.calendar_month), text: "캘린더"),
              Tab(icon: Icon(Icons.query_stats), text: "통계"),
            ],
          ),
        ),
        body: tabContainer()
    );
  }

중요한 부분은 TabBar() 입니다.

indicatorColor는 선택된 탭바 하단 인디케이터 색상,

tabs는 탭바에 표시될 탭을 작성해주면 됩니다.

icon과 text 등 원하는 것만 추가해도 됩니다.

그리고 body는 탭 선택 시 원하는 화면이 표시되도록 tabContainer 함수를 호출해줍니다.

 

 

5. 탭 선택 시 화면 연결 (tabContainer())

  StatelessWidget tabContainer() {
    switch (_selectedIndex) {
      case 0:
        return ScheduleScreen();
      case 1:
        return CalendarScreen();
      case 2:
        return StatsScreen();
    }
    return Container(child: Text("data"));
  }

 

선택된 탭(selectedIndex)에 따라 원하는 화면을 출력해주면 됩니다.

 

참고용 화면) ScheduleScreen, CalendarScreen(), StatsScreen()

class ScheduleScreen extends StatelessWidget {
  const ScheduleScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.green,
      child: Center(child: Text("스케줄 화면!", style: TextStyle(fontSize: 20),)),
    );
  }
}


class CalendarScreen extends StatelessWidget {
  const CalendarScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return  Container(
      color: Colors.blue,
      child: Center(child: Text("캘린더 화면!", style: TextStyle(fontSize: 20),)),
    );
  }
}


class StatsScreen extends StatelessWidget {
  const StatsScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return  Container(
      color: Colors.amber,
      child: Center(child: Text("통계 화면!", style: TextStyle(fontSize: 20),)),
    );
  }
}

 

예제 화면)

 

 

전체 소스코드)

// home_screen.dart

import 'package:colab_note/screens/schedule/calendar_screen.dart';
import 'package:colab_note/screens/schedule/schedule_screen.dart';
import 'package:colab_note/screens/schedule/stats_screen.dart';
import 'package:flutter/material.dart';

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen>
    with SingleTickerProviderStateMixin {
  late TabController _tabController;
  int _selectedIndex = 0;

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: 3, vsync: this);
    _tabController.addListener(
      () => setState(() => _selectedIndex = _tabController.index),
    );
  }

  @override
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Title"), backgroundColor: Colors.white),
      bottomNavigationBar: SizedBox(
        height: 70,
        child: TabBar(
          indicatorColor: Colors.red,
          labelColor: Colors.black,
          controller: _tabController,
          tabs: <Widget>[
            Tab(icon: Icon(Icons.schedule), text: "스케줄"),
            Tab(icon: Icon(Icons.calendar_month), text: "캘린더"),
            Tab(icon: Icon(Icons.query_stats), text: "통계"),
          ],
        ),
      ),
      body: tabContainer(),
    );
  }

  StatelessWidget tabContainer() {
    switch (_selectedIndex) {
      case 0:
        return ScheduleScreen();
      case 1:
        return CalendarScreen();
      case 2:
        return StatsScreen();
    }
    return Container(child: Text("data"));
  }
}

 

 

간단하게 구현 완료!

반응형

'IT > Flutter' 카테고리의 다른 글

[Flutter] Safe Area 적용 방법  (0) 2025.10.11