TabBar class
Material Design의 기본 탭 바.
기본 탭은 콘텐츠 창 상단, 상단 앱 바 아래에 배치됩니다. 주요 콘텐츠 목적지를 표시합니다.
일반적으로 AppBar 의 AppBar.bottom 부분 으로 생성되고 TabBarView 와 함께 사용됩니다.
공식 문서 코드
앱의 상단에 앱바가 위치해 있는 부분에서 카테고리 기능이 동작되거나 툴바 동작이 진행돼야 하는 상황이 오기 마련이다. 이럴 때 우리는 어떻게 제작을 해야 할까? 그 질문에 대한 대답은 TabBar 위젯을 쓰라는 것이다.
이 TabBar 위젯은 카테고리나 화면을 나누어 사용자 경험을 단순하고 직관적으로 구성하고 싶을 때 사용하는데 탭 기반의 내비게이션을 구현할 때 주로 TabBar와 함께 TabBarView, 그리고 이를 감싸는 DefaultTabController를 함께 사용하곤 한다.
이는 각각의 탭을 눌렀을 때 다른 콘텐츠 화면을 보여주고 싶을 때 유용하게 사용된다. 한번 알아보자.
하위 속성
| 속성명 | 타입 | 기본값 | 설명 |
| tabs | List<Widget> | – | 탭으로 사용할 위젯들의 리스트로, 최소 두 개 이상 필요 |
| controller | TabController? | null | 탭 전환을 제어하는 컨트롤러, 생략 시 DefaultTabController를 사용 |
| isScrollable | bool | false | 탭이 넘칠 경우 수평 스크롤 여부를 결정 |
| padding | EdgeInsetsGeometry? | null | 탭 바 전체에 적용되는 패딩 |
| indicatorColor | Color? | Theme | 선택된 탭 하단 표시선의 색상 |
| indicatorWeight | double | 2.0 | 선택된 탭 하단 표시선의 두께 |
| indicatorPadding | EdgeInsetsGeometry | EdgeInsets.zero | indicator에 적용되는 패딩 |
| indicator | Decoration? | null | indicator의 모양을 정의하는 데코레이션 |
| indicatorSize | TabBarIndicatorSize? | null | indicator의 크기를 탭 전체 또는 라벨 기준으로 지정 |
| labelColor | Color? | null | 선택된 탭 라벨의 색상 |
| labelStyle | TextStyle? | null | 선택된 탭 라벨의 텍스트 스타일 |
| labelPadding | EdgeInsetsGeometry? | null | 탭 라벨에 적용되는 패딩 |
| unselectedLabelColor | Color? | null | 선택되지 않은 탭 라벨의 색상 |
| unselectedLabelStyle | TextStyle? | null | 선택되지 않은 탭 라벨의 텍스트 스타일 |
| onTap | ValueChanged<int>? | null | 탭이 탭될 때 호출되는 콜백 함수 |
| physics | ScrollPhysics? | null | 스크롤 동작 방식을 제어 |
| splashFactory | InteractiveInkFeatureFactory? | null | Ink 효과의 렌더링 방식을 지정 |
| splashBorderRadius | BorderRadius? | null | splash 효과에 적용할 테두리 반경 |
| tabAlignment | TabAlignment? | null | 탭 내 정렬 방식 (start, center, fill 등) |
| textScaler | TextScaler? | null | 텍스트 스케일링 동작 정의 |
| indicatorAnimation | TabIndicatorAnimation? | null | indicator 애니메이션 동작을 지정 |
사용하기 전에 TabBar 를 컨트롤하기 위해선 TabController 속성의 controller 가 필요한데 먼저 컨트롤러를 지정해줘야 한다.
TabController 는 필수 파라미터로 length 와 vsync 를 받는데 vsync 를 넣기 위해서 먼저 믹스인을 넣어줘야 한다.
class _TestState extends State<Test> with TickerProviderStateMixin {
late TabController tabController = TabController(length: 3, vsync: this);
탭 컨트롤러를 만들 때는 late 로 지정하고 만들어주면 편하게 사용할 수 있다. length: 에는 자신이 만들 탭의 개수를 입력해 주면 된다. 본인이 간단한 두 화면을 만들고 싶다 하면 2를, 5개의 화면을 만들고 싶다- 하면 5를 넣어주면 되겠다.
이렇게 탭 바 위젯이 상태 부모 위젯이나 다른 부모 위젯에 의해 생성되어 명시적으로 생성된 탭 컨트롤러를 공유하는 것이 불편하다면 조금 아래에서 소개할 DefaultTabController 를 사용해도 괜찮다.
TabBar(
controller: tabController,
tabs: [
Tab(icon: Icon(Icons.home), text: '홈',),
Tab(icon: Icon(Icons.star), text: '즐겨찾기',),
Tab(icon: Icon(Icons.settings), text: '설정',),
],
)
이제 빌드 위젯 안에서 바로 사용해 주면 된다.
controller 에는 위에서 만든 컨트롤러를 넣어주면 되고 이제 tabs 안에는 우리가 배치할 아이템을 넣어주면 된다. 아이템은 Tab 이라는 위젯을 통해서 배치되게 된다. 이 tabs 파라미터는 List<Widget> 타입을 갖고 있어서 Tab 이 아닌 위젯을 배치해도 아무런 문제 없이 잘 작동한다. 또한 Tab 의 파라미터인 icon 도 타입이 Widget 이기 때문에 넣고 싶은 위젯 아무거나 넣어줘도 된다.
TabBar 라는 위젯은 조금 특이한 편에 속한다. 어째서 특이하냐고 한다면 이렇게 우리가 조작할 수 있는 TabBar 위젯과 그 TabBar 안에 속해있는 TabBarView 를 제작해야 하기 때문이다.

TabBarView 에는 이제 위젯을 배치해줘야 하는데 현재 코드에서는 탭바를 3개로 설정해 놨으니 3개의 위젯을 배치해 주면 되겠다.
TabBarView(
controller: tabController,
children: [
Center(child: Text('홈 화면')),
Center(child: Text('즐겨찾기 화면')),
Center(child: Text('설정 화면')),
],
)
얼추 비슷한 위젯이 하나 생각나지 않는가? 바로 IndexedStack 위젯이다. 이 탭바 위젯은 인덱시드스택 위젯과 거의 유사하다고 생각하면 편하다.
지금 나는 코드를 이런 형식으로 짜놨다.
Scaffold(
appBar: TabBar(...),
body: TabBarView(...),
)
이렇게 하면 아주 간단하게 탭바를 사용할 수 있게 되지만 실제로 제작을 하게 되면 Sacffold 에 바로 탭바를 위치시키는 경우는 잘 없어 필연적으로 Column 같은 위젯 안에 배치하게 되는데 그럴 때면 TabBarView 의 사이즈를 무조건 지정해줘야 한다.
Column(
children: [
TabBar(...),
Expanded(
child: TabBarView(...),
)
],
)
이런 식으로 Expanded 를 하여 화면 전체를 차지하게 하는 방식을 난 선호하는 편이다. 아니면 SizedBox 를 사용하여 직접적으로 지정해 줘도 된다.
이번에는 DefaultTabContoller 에 대해 알아보자. 이 위젯은 위에서 알려준 것보다 더 간단하게 탭바를 바로 구현할 수 있게 도와준다. 놀랍게도 컨트롤러를 선언하지 않아도 된다.
DefaultTabController(
length: 3,
child: Scaffold(
appBar: TabBar(
tabs: [
Tab(icon: Icon(Icons.home), text: '홈',),
Tab(icon: Icon(Icons.star), text: '즐겨찾기',),
Tab(icon: Icon(Icons.settings), text: '설정',),
],
),
body: TabBarView(
children: [
Center(child: Text('홈 화면')),
Center(child: Text('즐겨찾기 화면')),
Center(child: Text('설정 화면')),
],
),
),
)
이렇게 만들면 너무나도 간단하게 컨트롤러를 만들지도 않고 바로 탭 동작을 할 수 있게 된다. 정말 화면에서 탭바가 내비게이션의 역할만 수행한다면 이 위젯을 쓰는 것을 추천한다. 다만 네비게이션 외의 콜백함수를 실행해야 한다든가 하는 그런 것들은 당연지사 controller 를 만들어서 사용하는 것이 좋다.
TabBar.secondary()
TabBar 에는 생성자가 하나 있는데 바로 TabBar.secondary 이다. 이름에서도 알 수 있듯이 탭이 두 개밖에 없다면 사용하기 좋은 위젯인데 그냥 TabBar 와 동작에는 전혀 차이가 없다. 다만 UI 적인 부분이 조금 달라지게 된다.
![]() |
![]() |
보이는 것과 같이 하단의 인디케이터가 달라지게 된다. 일반적인 탭바(왼쪽)은 그냥 자그마 낳게 인디케이터로 표시가 되지만 탭바 세컨더리는 인디케이터가 화면의 반을 꽉 채우는 모습이다.
당연하겠지만 이 생성자를 사용하는 데에 있어서 주의해야 할 점은 탭의 개수가 2개여야 한다는 점이다. 3개 막 이렇게 되면 바로 오류가 나버린다.
탭바도 디자인을 먹여줄 수 있다. unsunselected 가 앞에 붙은 파라미터를 사용하면 선택되지 않은 탭의 속성을, label 이 붙은 파라미터를 사용하면 전체적인 스타일과 선택되었을 때의 색상을 지정해 줄 수 있다.
unselectedLabelStyle: TextStyle(
color: Colors.blue,
fontWeight: FontWeight.w100
),
labelStyle: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w900
)
여기서 unselectedLabelStyle 속성을 사용해 줬기에 labelStyle 과 구분되어 적용되게 된다. labelStyle 만을 사용했다면 전체가 그 스타일을 먹게 될 것이다.

위에서 secondary 생성자를 사용하면 인디케이터가 늘어난다고 말했는데 사실 그냥 설정으로 조절할 수 있다.
또한 색상과 패딩도 다 먹여줄 수 있다.
indicatorColor: Colors.black,
indicatorSize: TabBarIndicatorSize.tab,
indicatorPadding: EdgeInsets.symmetric(horizontal: 15)
indicatorSize 를 TabBarIndicatorSize.tab 으로 해놓게 되면 인디케이터의 크기가 탭의 크기를 다 차지하게 된다.

여기서 주의해야 할 점은 indicator 속성 사용 시 Color 라든가 Size 라던가 전부 무시되어 버리니 가급적이면 인디케이터는 내가 사용한 속성들로 사용하는 것이 좋다.
이렇게 TabBar 위젯에 대해서 알아보았다. 이 위젯은 놀랍게도 탭 아이템을 클릭해도 다른 화면으로 넘어가지지만 TabBatView 가 위치해 있는 곳을 스와이프 하면 다른 화면으로 그대로 넘어가는 것을 알 수 있다. 이 위젯은 정말 이러한 탭을 만드는 시간 자체와 애니메이션을 또 집어넣은 시간 이런 것을 전부 줄여주기 때문에 꼭 사용해야 하는 위젯이 되겠다. 암튼 도움이 되었길 바라며 마치겠다.

