TabBarView
의 TabController
를 활용하여 탭 인덱스에 따라 페이드되는 위젯을 구현할 수 있다.
TabController.animation
: 탭 이동에 따라 변화가 발생하는 listener
로, 이것을 listen하여 AnimatedBuilder
를 만들면 탭 이동에 따라 변화하는 위젯을 작성할 수 있다.
TabController.indexIsChanging
: TabBarView
의 index가 변화 중일 때, 변화가 스와이프로 이루어졌는지, TabBar
조작이나 animateTo
등의 메소드로 변화했는 지를 체크할 수 있다.
인덱스가 2 이상 변화했을 때, 전체 변화가 liner하게 적용되는 PageView
와 달리 TabBarView
는 변화가 1 이상인 경우 중간 페이지를 스킵하게 되기 때문에, 페이지 이동을 직접 참조하는 경우 이 변수의 사용이 중요해진다.
TabController.previousIndex
: TabController.indexIsChanging
이 true
인 경우, 이 값을 사용해 변화가 시작된 시점의 탭 인덱스를 구할 수 있다. 현재 진행 목표 인덱스인 TabController.index
와 함께 사용해서 교차 등을 구현할 수 있다.
TabController.offset
: 탭이 변화 중일 때 현재 중간 인덱스의 상대 값을 나타낸다. 때문에 인덱스 2 이상 이동하여 중간 탭이 스킵되더라도 liner한 값으로 offset이 표기된다.
위 기능을 활용하여 페이지 변화에 따라 Fade되는 위젯을 구현한 샘플이다.
Widget _buildFadeWidgetByTabIndex(TabController tabController) {
return AnimatedBuilder(
//animation을 참조해야 중간 인덱스 변화를 참조할 수 있다.
animation: tabController.animation!,
builder: (_, __) {
int previousIndex;
double progress; //현재 이동 진행 상태를 0-1 값으로 연산
//탭이 TabBar 조작 등으로 변경되고 있는 경우
if (tabController.indexIsChanging) {
previousIndex = tabController.previousIndex;
var distance = tabController.previousIndex - tabController.index;
progress = 1 - tabController.offset / distance;
} else {
//스와이프 등으로 좌우 이동하는 경우, offset의 음수 양수 여부를 통해 이동 예정 위치를 구한다
var offset = tabController.offset;
previousIndex =
max((tabController.index + (offset < 0 ? -1 : 1)), 0);
progress = 1 - offset.abs();
}
return Stack(
children: [
_buildSomeWidgetByTabIndex(previousIndex),
Opacity(
//progress값을 투명도에 적용, Fade모션을 구현한다
opacity: progress,
child: _buildSomeWidgetByTabIndex(tabController.index),
),
],
);
});
}