본문 바로가기

대외활동

[Pure App] Bottomnavigationbar 적용 / Provider 이용 (with Flutter)

결과

 

 

 


 

 

NavigationBar 클래스 이용

 

- destinations: 리스트 형식으로 메뉴 형성

- selectedIndex: 위의 리스트에서 선택한 순서값을 저장

- onDestinationSelected : destinations의 리스트 중 하나가 선택되면 호출

 

 

 

 

NavigationBar의 destinations 에서 요소들 중 한 개를 클릭하면 onDestinationSelected가 호출되고,

콜백으로 selectedIndex의 값을 업데이트한다.

selectedIndex가 업데이트 되면 NavigationBar는 다시 빌드되면서 선택한 요소로 이동!

int tabPageIndex = 0;

@override
Widget build(BuildContext context) {
  return NavigationBar(
      destinations: [
        NavigationDestination(
            icon: Icon(Icons.home_outlined),
            selectedIcon: Icon(Icons.home),
            label: "Home"
        ),
        NavigationDestination(
            icon: Icon(Icons.add_comment_outlined),
            selectedIcon: Icon(Icons.add_comment),
            label: "Memory"
        ),
        NavigationDestination(
            icon: Icon(Icons.people_outline),
            selectedIcon: Icon(Icons.people),
            label: "Community"
        ),
        NavigationDestination(
            icon: Icon(Icons.star_border_outlined),
            selectedIcon: Icon(Icons.star),
            label: "My"
        )
    ],
    selectedIndex: tabPageIndex,
    onDestinationSelected: (value) {
      setState(() {
        tabPageIndex = value;
      });
    },
    indicatorColor: Colors.amberAccent,
  );
}

 

indicatorColor는 선택 시 요소의 배경 색을 설정한 것이다.

 


 

 

여기에 Provider 적용

https://pub.dev/packages/provider/install

 

provider install | Flutter package

A wrapper around InheritedWidget to make them easier to use and more reusable.

pub.dev

 

pubspec.yaml 파일의 dependencies에 

provider: ^6.1.2

입력 후 Pub get

 

dart 파일 하나 생성 후 코드 입력

import 'package:flutter/material.dart';

class NavigationIndexProvider extends ChangeNotifier{
  int _currentPageIndex = 0;
  int get currentPageIndex => _currentPageIndex;
  
  void setCurrentPageIndex(int index){
    _currentPageIndex = index;
    notifyListeners();
  }
}

 

provider를 쓰는 이유!

-> main.dart에 모든 코드를 넣지 않을 거라서!

 

다른 파일에서 생긴 변화를 다른 파일에서 감지하고 화면에 반영해야하기에 

연결할 Provider 사용

 

 


 

 

 

main_bottom_navigation_bar

@override
Widget build(BuildContext context) {
  var navigationIndexProvider = Provider.of<NavigationIndexProvider>(context, listen: false);

  return NavigationBar(
      destinations: [
        NavigationDestination(
            icon: Icon(Icons.home_outlined),
            selectedIcon: Icon(Icons.home),
            label: "Home"
        ),
        NavigationDestination(
            icon: Icon(Icons.add_comment_outlined),
            selectedIcon: Icon(Icons.add_comment),
            label: "Memory"
        ),
        NavigationDestination(
            icon: Icon(Icons.people_outline),
            selectedIcon: Icon(Icons.people),
            label: "Community"
        ),
        NavigationDestination(
            icon: Icon(Icons.star_border_outlined),
            selectedIcon: Icon(Icons.star),
            label: "My"
        )
    ],
    selectedIndex: navigationIndexProvider.currentPageIndex,
    onDestinationSelected: (value) {
      setState(() {
        navigationIndexProvider.setCurrentPageIndex(value);
      });
    },
    indicatorColor: Colors.amberAccent,
  );
}

 

selectedIndex에서는 currentPageIndex값을 가져오는 get함수를 사용했고,

onDestinationSelected에서는 setCurrentPageIndex인 set함수를 사용해 바뀐 index값으로 저장했다.

 

 

 

main_screen

@override
Widget build(BuildContext context) {

  var navigationIndexProvider = Provider.of<NavigationIndexProvider>(context, listen: false);
  var currentIndex = navigationIndexProvider.currentPageIndex;
  
  navigationIndexProvider.addListener(() { 
    setState(() {
      currentIndex = navigationIndexProvider.currentPageIndex;
    });
    
  });
  return Container(
    child: [
    Center(child: Text("Home")),
    Center(child: Text("Memory")),
    Center(child: Text("Community")),
    Center(child: Text("My"))
    ][currentIndex]
  );
}

main화면에서도 Provider를 선언하고 Provider의 리스너 등록했다.

Container의 index값을 currentIndex값으로 바꿨다.

 

여기서 addListener는

provider 파일의 setCurrentPageIndex함수 안의 

notifyListeners();에 의해 동작한다.

notifyListeners()는 provider에 등록된 모든 리스너 실행하기 때문이다.

 

 

 

main

home: ChangeNotifierProvider(
  create: (BuildContext context) => TabPageIndexProvider(),
  child: Scaffold(
    bottomNavigationBar: MainBottomNavigationBar(),
    body: MainScreen(),
  ),
),

마지막으로 main의 home에서는

ChangeNotifierProvider로 변화에 대한 구독을 하고,

create를 사용해서 ChangeNotifier를 생성한다.

 

ChangeNotifierProvider는 하나만 구독할 수 있으니 여러 개를 하려면

MultiProvider를 이용해야 한다.

 


 

Provider의 상태를 받아오는 방법

 

1. Provider.of: 해당 위젯 전체가 리빌드

 -> 가벼운 위젯은 괜찮음

- 자동 리빌드(필요에 의해 방지 가능)

- 간편함(코드 짧음), 일관성(상태에 직접 접근)

 

2. Consumer: 변화가 필요한 위젯만 리빌드 (자식 위젯 중에서)

 -> 여러 효과나 연산이 복잡한 위젯일 경우 추천

- 코드 양 더 많음

- 최적화(성능 향상)

- 유연성: 상태 변경 시 반영할 콜백 함수 제공

 

현재 코드에서는 상태가 변경될 때마다 해당 위젯이 리빌드되어야 하므로

Provider.of를 사용하는 것이 더 간단하고 적합하다.

MainBottomNavigationBar는 하단 네비게이션 바이기 때문에 해당 상태가 변경될 때마다 리빌드되는 것이 일반적이다.