본문 바로가기
Flutter

[flutter] TabBar disable 하는 방법

by 개발짜 2025. 1. 27.

 

 

 

 

일기 정보를 가져오는 데 한글 일기 부분이 null 일 때 한국어 TabBar 부분을 비활성화 하고 싶다. 사용자에게 비활성화가 되었다는 것을 확실히 표현하기 위해서는

1. 탭을 눌렀을 때 이동이 안되어야 하고,

2. 한국어 글씨가 회색으로 고정이 되어야하며,

3. 클릭했을 때 눌리는 효과를 없애야 한다.

 

먼저 tab 이 이동하는 것을 불가능 하게 하려면 해당 화면이 init 될 때 한국어 일기가 있는지 체크한 후 TabCotroller 에 리스너를 추가한다. 한국어 tab 을 누르면 index 값이 1로 변하는 데 이때 다시 index 값을 0으로 변경하면 tab 이 변경되지 않는다.

class _DayLogDetailPageState extends State<DayLogDetailPage>
    with TickerProviderStateMixin {
  late TabController _tabController;

  /// 모국어로 작성되어 있는지 체크
  late bool isWrittenNativeDayLog;

  @override
  void initState() {
    super.initState();
    // _tabController 초기화
    _tabController = TabController(length: 2, vsync: this);
    // 한국어 일기가 작성되어있는지 체크
    isWrittenNativeDayLog = widget.dayLog.native != null ? true : false;
    // 한국어 일기가 작성되어 있지 않으면 tab bar 비활성화
    if (!isWrittenNativeDayLog) {
      // controller 에 listener 추가
      _tabController.addListener(() {
        // 한국어 탭(1) 이 눌리면
        if (_tabController.index == 1) {
          setState(() {
            // 영어 탭(0) 으로 변경해서 이동 불가능하도록
            _tabController.index = 0;
          });
        }
      });
    }
  }

 

이 때 주의

tabbar view 는 옆으로 스크롤하면 tab 이 이동하는 게 디폴트로 되어있다. 스크롤링이 활성화되어 있으면 복잡하므로 오직 탭 클릭으로만 페이지 이동할 수 있도록 physics: NeverScrollableScrollPhysics() 을 추가한다.

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: DayLogDetailAppBar(
        dayLog: widget.dayLog,
        tabController: _tabController,
        isWrittenNativeDayLog: isWrittenNativeDayLog,
      ),
      body: TabBarView(
        // 스크롤로 tab 변경 금지
        physics: NeverScrollableScrollPhysics(),
        controller: _tabController,
        children: [
          ForeignDetailView(dayLog: widget.dayLog),
          NativeDetailView(dayLog: widget.dayLog),
        ],
      ),
    );
  }
}

 

 

한국어 일기가 없을 경우 텍스트 색상이 회색으로 표시되도록 text 스타일을 지정해준다.

  Tab _tab(String text, {bool isWritten = true}) {
    return Tab(
      icon: Text(
        text,
        // 한국어 일기가 작성되어 있으면 검정색, 아니면 옅은 회색
        style: isWritten
            ? CustomText.header_02_SB
            : CustomText.header_02_SB.copyWith(color: CustomColors.grey_400),
      ),
    );
  }
  
  class CustomText {
  static TextStyle header_02_SB = TextStyle(
    fontSize: 16,
    fontWeight: FontWeight.w600,
    height: 1.6,
    color: CustomColors.grey_900,
  );
}

 

 

tab 을 눌렀을 때 나오는 물결 모양을 없애기 위해서는 TabBar 의 overlayColor 를 지정해야한다. 투명으로 지정할 경우 눌렀을 때 아무런 효과가 없는 것 처럼 보이므로 비활성화 되어있다는 것을 확실히 표현할 수 있다.

class DayLogDetailAppBar extends StatelessWidget
    implements PreferredSizeWidget {
  DayLog dayLog;
  TabController tabController;
  bool isWrittenNativeDayLog;

  DayLogDetailAppBar({
    super.key,
    required this.dayLog,
    required this.tabController,
    required this.isWrittenNativeDayLog,
  });

  @override
  Widget build(BuildContext context) {
    return AppBar(
      title: Text(
        LDateFormat.dayLogFormat(DateTime.parse(dayLog.date)),
        style: CustomText.header_01_SB,
      ),
      bottom: TabBar(
        // tab bar indicator 크기
        indicatorSize: TabBarIndicatorSize.tab,
        // tab bar 분리되어 있는 색상
        dividerColor: CustomColors.grey_200,
        // tab bar 누를 때 나오는 splash 색상
        overlayColor: WidgetStatePropertyAll(
          // 작성되어 있으면 누를 때 회색 컬러를, 아니면 투명색
          isWrittenNativeDayLog ? CustomColors.bg_100 : Colors.transparent,
        ),
        controller: tabController,
        tabs: <Widget>[
          _tab('English'),
          _tab('한국어', isWritten: isWrittenNativeDayLog),
        ],
      ),
      actions: [
        DayLogDeleteIcon(
          dayLogKey: dayLog.keyDate,
        ),
      ],
    );
  }

  @override
  Size get preferredSize => Size.fromHeight(100);
}

 

 

완성된 페이지

 

 

댓글