본문 바로가기
관리자

Programming-[CrossPlatform]/Flutter

[작성중][제철음식 알리미] bottomNavBar, didChangeDependencies, pageController

728x90
반응형

제철음식 알리미 앱을 제작하며 학습했던 내용들을 정리한다.

 


1. BottomNavBar

 

 

bottomNavBar 요소를 통해서 페이지를 이동할 수 있도록 했다. Scaffold 내부에 bottomNavigationBar 인자로 아래와 같이 BottomNavBar를 추가했다.

bottomNavigationBar: BottomNavBar(
  selectedIndex: _selectedIndex,
  onItemTapped: _onItemTapped,
)

 

여기서 _selectedIndex, _onItemTapped를 통해 현재 선택된 index 값과 홈 또는 검색 아이콘이 클릭되었을 때의 행동을 정의한다. selectedIndex 값은 홈페이지의 index 값을 0, 검색 페이지의 index 값을 1로 두었다. 그리고 onItemTapped에서 변경이 감지되도록 하고 조건에 따라 어떤 페이지로 이동하고 값을 관리할지 결정한다.

 

Navigator.canPop을 통해 현재 Navigator 스택에 페이지가 남아있는지 검사하는 부분은 스택에 이미 페이지가 쌓여있는 경우 페이지를 더 쌓지 않고 현재 페이지를 다른 페이지로 전환하도록 하기 위함이다. 스택에 페이지가 계속 쌓이면 사용자가 뒤로가기를 계속 해야하는 불편함이 생길 수 있다.

 

pushReplacementNamed, pushNamed에 대해서는 아래 글에서 정리한 바가 있다.

https://whitepro.tistory.com/1019

 

class _HomeViewState extends State<HomeView> {
  // ...생략

  final PageController _pageController = PageController();
  int _selectedIndex = 0;
  
  // ... 중략
  void _onItemTapped(int index) {
    if (index == _selectedIndex) {
      return;
    }
    setState(() {
      _selectedIndex = index;
    });
    if (Navigator.canPop(context)) {
      if (index == 0) {
        Navigator.pushReplacementNamed(context, '/home',
            arguments: {'selectedIndex': 0});
      } else if (index == 1) {
        Navigator.pushReplacementNamed(context, '/search',
            arguments: {'selectedIndex': 1});
      }
    } else {
      if (index == 0) {
        Navigator.pushNamed(context, '/home', arguments: {'selectedIndex': 0});
      } else if (index == 1) {
        Navigator.pushNamed(context, '/search',
            arguments: {'selectedIndex': 1});
      }
    }
  }
  
}

 

 

이렇게 BottomNavBar 및 _selectedIndex, _onItemTapped를 정의하는 부분은 위에서 다룬 홈페이지 뿐만 아니라 상세 페이지 등 네비게이션이 필요하고 그 상태가 유지되어야하는 모든 페이지에 똑같이 추가해주었다. 중복 코드가 발생하기 때문에 공통화하고 싶었는데, 방법을 찾지 못했고, 페이지가 많지 않아서 일단은 그대로 적용했었다.

 

 

검색화면도 마찬가지다.

 

예를 들어 검색화면의 코드에도 아래와 같이 코드가 작성되어있다.

class SearchFoodView extends StatefulWidget {
  @override
  _SearchFoodViewState createState() => _SearchFoodViewState();
}

class _SearchFoodViewState extends State<SearchFoodView> {
  //...생략
  int _selectedIndex = 0;

    //...생략

  void _onItemTapped(int index) {
    if (index == _selectedIndex) {
      return;
    }
    setState(() {
      _selectedIndex = index;
    });
    if (index == 0) {
      Navigator.pushNamedAndRemoveUntil(context, '/home', (route) => false, arguments: {'selectedIndex': 0});
    } else if (index == 1) {
      Navigator.pushReplacementNamed(context, '/search', arguments: {'selectedIndex': 1});
    }
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    final arguments = ModalRoute.of(context)?.settings.arguments as Map?;
    if (arguments != null && arguments.containsKey('selectedIndex')) {
      setState(() {
        _selectedIndex = arguments['selectedIndex'];
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
        //...중략
          bottomNavigationBar: BottomNavBar(
            selectedIndex: _selectedIndex,
            onItemTapped: _onItemTapped,
          )),
    );
  }
}

 

728x90
반응형