21. 플러터 : 탭바

이번에는 가장 일반적인 형태로 사용하는 탭바 인터페이스를 살펴보자.

탭바 인터페이스의 구현은 TabController 클래스가 담당한다.
탭바는 보통 화면 하단에 위치한다.
사실 위쪽에 탭바가 있으면 '바(bar)'를 붙이지 않고 그냥 탭(tab)이라고 부른다.

탭바 인터페이스로 구현하는 이유는
탭에 연결된 화면이 완전히 달라지기 때문이다.
각각의 화면은 일부 연관되어 있을 수도 있지만, 전혀 상관없는 경우가 많다.
그래서 이번 예제에서도 단순하긴 하지만
완벽하게 다른 화면으로 각각의 화면을 구성했다.

탭바의 아이콘은 형식적으로 붙인 것이고
제목에 있는 색상에 맞게 화면 배경색을 처리했다.


각각의 화면은 보통 클래스로 구현을 한다.
색상에 맞게 Red, Green, Blue 클래스를 간단하게 만들었다.

배경색을 처리하기 위해 Container 클래스로 감쌌고
Card 위젯의 여백을 흉내내기 위해 maring 옵션도 일부 줬다.

import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(home: MyTabs()));

// TabController 객체를 멤버로 만들어서 상태를 유지하기 때문에 StatefulWidget 클래스 사용
class MyTabs extends StatefulWidget{
@override
MyTabsState createState() => MyTabsState();
}

// SingleTickerProviderStateMixin 클래스는 애니메이션을 처리하기 위한 헬퍼 클래스
// 상속에 포함시키지 않으면 탭바 컨트롤러를 생성할 수 없다.
// mixin은 다중 상속에서 코드를 재사용하기 위한 한 가지 방법으로 with 키워드와 함께 사용
class MyTabsState extends State<MyTabs> with SingleTickerProviderStateMixin {
// 컨트롤러는 TabBar와 TabBarView 객체를 생성할 때 직접 전달
TabController controller;

// 객체가 위젯 트리에 추가될 때 호출되는 함수. 즉, 그려지기 전에 탭바 컨트롤러 샛성.
@override
void initState(){
super.initState();

// SingleTickerProviderStateMixin를 상속 받아서
// vsync에 this 형태로 전달해야 애니메이션이 정상 처리된다.
controller = TabController(vsync: this, length: 3);
}

// initState 함수의 반대.
// 위젯 트리에서 제거되기 전에 호출. 멤버로 갖고 있는 컨트롤러부터 제거.
@override
void dispose(){
controller.dispose();
super.dispose();
}

@override
Widget build(BuildContext context){
return Scaffold(
appBar: AppBar(title: Text('교통 수단')),
body: TabBarView(
controller: controller, // 컨트롤러 연결
children: [Red(), Green(), Blue()]
),
bottomNavigationBar: Container(
child: TabBar(
controller: controller, // 컨트롤러 연결
tabs: [
// 아이콘은 글자 수 같은 걸로 선택. 의미 없음. 제목에 들어간 색상은 중요.
Tab(icon: Icon(Icons.card_travel), text: '빨강'),
Tab(icon: Icon(Icons.donut_small), text: '초록',),
Tab(icon: Icon(Icons.table_chart), text: '파랑'),
]
),
color: Colors.blueGrey,
),
);
}
}

// Card 위젯 구현
class Red extends StatelessWidget {
@override
Widget build(BuildContext context){
return Card(color: Colors.red);
}
}

// Text 위젯 구현
class Green extends StatelessWidget {
@override
Widget build(BuildContext context){
return Container(
child: Center(
child:Text('GREEN', style: TextStyle(fontSize: 31, color: Colors.white))
),
color: Colors.green,
margin: EdgeInsets.all(6.0),
);
}
}

// Icon 위젯 구현
class Blue extends StatelessWidget {
@override
Widget build(BuildContext context){
return Container(
child: Center(
child: Icon(Icons.table_chart, size: 150, color: Colors.white),
),
color: Colors.blue,
margin: EdgeInsets.all(6.0),
);
}
}


탭바 인터페이스는 각각의 화면을 개별적인 클래스로 처리하기 때문에
당연하게 개별 파일에 저장하게 된다.
앞의 예제를 다중 파일 형태로 수정해 보자.

1.
Red, Green, Blue 클래스를 잘라내서 my_screen.dart 파일을 만들어서 붙여넣자.
my_screen.dart 파일의 꼭대기에는 당연히 material.dart 파일 import문이 있어야 한다.

2.
main.dart 파일에 아래 코드를 추가한다.
다른 파일과 연동할 때는 아래처럼 사용한다. 점(dot)은 현재 폴더를 가리키는 문법이다.

import './my_screen.dart' as my_screen;


3.
TabBarView 객체를 생성하는 children 옵션을 아래처럼 수정한다.
참조하려는 클래스가 현재 파일이 아니라 my_screen 파일에 있다고 알려준다.

children: [
my_screen.Red(),
my_screen.Green(),
my_screen.Blue(),
]