개인 프로젝트 풀밭을 개발하며 CampusView의 UI와 기능을 개발하였는데 문제가 생겼다. 자세한 개발 내용은 위의 링크를 누르면 볼 수 있다.
CampusView는 DynamicTabBar on Scroll으로 Scroll과 TabBar를 서로 연동하여 Tab을 눌렀을 때 자동으로 스크롤이 되거나 혹은 스크롤을 하였을때 Tab이 자동으로 변경되는 기능이 있다.
이 때 발생한 문제는 Tab을 눌러 스크롤이 자동으로 설정된 값을 스크롤 될 때 다른 Tab을 누르게 되면
scrollToIndex
함수가 중복 실행이 되어 코드가 꼬이는 문제가 발생하였다.
한 번 어떤 상황인지 화면을 봐보자.
스크롤 이동이 끝난 후 Tab을 눌러 잘 작동 되는 모습
스크롤 이동이 끝나기 전 Tab을 눌러 오류가 있는 화면
TabBar 코드를 보면 onTap시 해당 Tab의 index를 scrollToIndex함수에 파라미터 값으로 넣고 실행이 된다.
그러면 scrollToIndex가 실행한다면 bool isRunning을 true로 하고 실행이 끝나면 false로 바꾸자.
scrollToIndex함수는 milliseconds: 600 duration이니 onTapDynamicTabBar
함수를 만들어 지연을 시키자!
// TabBar 코드
TabBar(
tabs: [
1번 텍스트 탭,
2번 텍스트 탭,
3번 텍스트 탭,
],
// Tap시 실행되는 함수.
onTap: (int index) => scrollToIndex(index),
),
/// Animate To Tab
void animateToTab() {
late RenderBox box;
for (var i = 0; i < campusCategories.length; i++) {
box = campusCategories[i].currentContext!.findRenderObject() as RenderBox;
Offset position = box.localToGlobal(Offset.zero);
if (scrollController.offset >= position.dy) {
DefaultTabController.of(tabContext!).animateTo(
i,
duration: const Duration(milliseconds: 100),
);
}
}
}
/// Scroll to Index
void scrollToIndex(int index) async {
scrollController.removeListener(animateToTab);
final categories = campusCategories[index].currentContext!;
await Scrollable.ensureVisible(
categories,
duration: const Duration(milliseconds: 600),
);
scrollController.addListener(animateToTab);
}
onTapDynamicTabBar
함수 생성isRunning 변수값을 스크롤이 이동되는 시간만큼 지연시켜 변경해주어 에러를 방지한다. 입력 후 0.6초를 기다리고 0.6초동안 스크롤이 실행되다보니 화면 이동이 느려 0.1초로 변경하였다.
// TabBar 코드
TabBar(
tabs: [
1번 텍스트 탭,
2번 텍스트 탭,
3번 텍스트 탭,
],
// Tap시 실행되는 함수.
onTap: (int index) => onTapDynamicTabBar(index), // 함수 변경
),
void onTapDynamicTabBar(int index) {
setState(() {
isRunning = true; // 실행 중 상태로 설정
});
// 비동기적으로 잠시 대기 후 scrollToIndex 호출
Future.delayed(const Duration(milliseconds: 100), () { // 0.1초로 변경
if (isRunning) {
scrollToIndex(index); // index로 스크롤
setState(() {
isRunning = false; // 실행 종료 상태로 설정
});
}
});
}
AbsorbPointer
클래스** 생성isRunning이 true일때 화면 입력을 감지하지만 무시할 수 있는 **AbsorbPointer
** 사용하여 실행중에 화면입력을 방지한다.
사실 지연을 시켜 입력을 무시할 필요는 없지만 혹시 모를 에러를 대비하여 AbsorbPointer를 사용하였다.