GetX와 ConvexBottomBar를 함께 사용해보자

Clean Code Big Poo·2023년 3월 9일
0

Flutter

목록 보기
17/38
post-thumbnail

Overview

최근 REAFLA에서 구글 코리아에 제출할 페이플 사용사례로 활용하기 위해 토이프로젝트를 시작하였다.. 꼽사리로 같이 끼게 됨.
겸사겸사 개인 프로젝트로 비슷한 Stack을 사용하여 만들어 보고자 한다.

맨 먼저 중앙에 동그란 버튼이 있는 BottomNavi를 구현해 보자.

스스로 위젯을 만들어보는 것도 도움이 되겠지만 그건 앱 사이클을 완전히 만들어보고 나서 생각하는 거로~!

고로 멋쟁이 개발자님들이 만들어 주신 BottomNavi를 설치하여 GetX와 함께 사용해 보자.

여기에서 원하는 BottomNavi 골라 잡아~!

ConvexBottomBar

설치

ConvexBottomBar Doc

installing 탭에 들어가 설치하자.

Theme

propertydescription
backgroundColorBar의 배경색
gradientBar 배경색을 그라데이션 할 수 있다.
heightBar의 높이
colorTab Icon과 Text의 색상
activeColor활성화 된 Tab Icon/Text의 색상
curveSizeconvex 의 크기
topAppBar를 기준으로 볼록한 모양의 제일 윗단
cornerRadiusBar의 양 끝단의 굴곡도
style여기에서 supported style를 확인!
chipBuilderConvexAppBar.badge를 커스텀하여 쓸 수 있다.

코드

//bottom_nav_view.dart

import 'package:convex_bottom_bar/convex_bottom_bar.dart';//import this
import 'package:get/get.dart';// for GetX

class BottomNavView extends GetView<BottomNavController> {
  const BottomNavView({
    Key? key,
    required this.onTapPressed,
  }) : super(key: key);

  final Function(int index) onTapPressed;

  
  Widget build(BuildContext context) {
    return StyleProvider(
      style: ConvexStyleProvider(),
      child: ConvexAppBar(
        curve: null,
        color: system100,
        backgroundColor: Colors.white,
        style: TabStyle.fixedCircle,
        activeColor: primary000,
        cornerRadius: 20,
        height: 60,
        items: [
          TabItem(
            title: translation(context).home,
            icon: Icons.home,
          ),
          TabItem(
            title: translation(context).cafe,
            icon: Icons.assistant_photo_rounded,
          ),
          TabItem(
            title: translation(context).story,
            icon: Icons.add_reaction_rounded,
          ),
          TabItem(
            title: translation(context).store,
            icon: Icons.add_shopping_cart_rounded,
          ),
          TabItem(
            title: translation(context).my_info,
            icon: Icons.account_box,
          ),
        ],
        onTap: (int index) {
          onTapPressed(index);
        },
      ),
    );
  }
}

class ConvexStyleProvider extends StyleHook {
  
  double get activeIconSize => 40;

  
  double get activeIconMargin => 10;

  
  double get iconSize => 20;

  
  TextStyle textStyle(Color color, String? fontFamily) {
    return text9Bold.copyWith(color: color);
  }
}

Theme 에서 내용과 비교하자면

backgroundColor: Colors.white, // 배경색 white
color: system100,//Tab icon/text 색상
activeColor: primary000,//활성화된 Tab icon/text 색상
cornerRadius: 20,//양 끝단의 굴곡
style: TabStyle.fixedCircle, //가운데 동그라미 버튼 고정

아래와 같은 모습의 Bottom Navi가 완성된다.

GetX

소스코드를 들여다보면 onTab()에 index를 받아 onTapPressed를 호출하는 callBack 함수로 되어 있다. 이제 BottomNavView를 호출하는 곳을 살펴보자.

BottomNavigationScreen

// bottom_nav_screen.dart

class BottomNavigationScreen extends StatelessWidget {
  BottomNavigationScreen({
    Key? key,
  }) : super(key: key);

  final pages = [
    HomePage(),
    CafePage(),
    StoryPage(),
    StorePage(),
    MyInfoPage()
  ];//Bottomnavi에 물려있는 Page들

  BottomNavController bottomNavController = Get.put(BottomNavController());

  
  Widget build(BuildContext context) {
    return Scaffold(
      body: Obx(//here
        () => IndexedStack(//here
          children: pages,
          index: bottomNavController.selectedIndex.value,
        ),
      ),
      bottomNavigationBar: BottomNavView(
        onTapPressed: (int index) {
          bottomNavController.ChangeIdex(index);//here
        },
      ),
    );
  }
}

IndexedStack를 통해 BottomNavi가 Tab 이동마다 rebuild되는 현상을 막을 수 있다.
BottomNavController 의 ChangeIdex를 호출하여 index 의 현재값을 바꾸어 주고 Obx를 이용하여 값을 notify 한다.

BottomNavController

//bottom_nav_controller.dart

import 'package:get/get.dart';

class BottomNavController extends GetxController {
  var selectedIndex = 1.obs;//BottomNavigationScreen의 Obs에서 바라본 값이 요놈이다.
  var textValue = 0.obs;

  void ChangeIdex(int index) {
    selectedIndex.value = index;
  }

  void IncreaseValue() {
    textValue.value++;
  }//이건 나중에 swipe로 page 전환하려고 미리 맹글어 놓음.
}

Route

//app_pages.dart

...
GetPage(
      name: _Paths.BOTTOM_NAV,
      page: () => BottomNavigationScreen(),
      binding: BottomNavBinding(),
      children: [
        GetPage(
          name: _Paths.HOME,
          page: () => const HomePage(),
          binding: HomeBinding(),
        ),
        GetPage(
          name: _Paths.MY_INFO,
          page: () => const MyInfoPage(),
          binding: MyInfoBinding(),
        ),
        GetPage(
          name: _Paths.STORE,
          page: () => const StorePage(),
          binding: StoreBinding(),
        ),
        GetPage(
          name: _Paths.STORY,
          page: () => const StoryPage(),
          binding: StoryBinding(),
        ),
        GetPage(
          name: _Paths.CAFE,
          page: () => const CafePage(),
          binding: CafeBinding(),
        ),
      ],
    ),
    ...

마지막으로 BottomNavigation에 물려있는 Page들을 children에 물려(?)준다. ㅎㅎ 이렇게 하면 StatelessWidget가 아닌 GetView 를 extends 받은 View 를 만들 수 있다. 이와 같이 구성한 이유는 각각의 controller를 만들어주기 위함이다.. 물론 만드는 사람에 따라 BottomNavController을 전달할 수도 있겠지만...
이대로 진행하다가 문제시 수정하러옴 ㅜ.ㅜ

0개의 댓글