[Flutter] IndexedStack 과 PageView 의 차이

merci·2023년 4월 20일
0

Flutter

목록 보기
23/24

IndexedStack

IndexedStack 에 등록된 페이지를 한번에 렌더링 한다.
다른 페이지를 보여주지 않을뿐 로그를 확인하면 모두 렌더링 되어 있는것을 알 수 있다.
네이게이션바에 선택된 인덱스 상태로 IndexedStack에 등록된 페이지를 렌더링 하게 된다.

class MainPage extends StatefulWidget {
  const MainPage({Key? key}) : super(key: key);

  
  State<MainPage> createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
  int _selectedIndex = 0;

  
  Widget build(BuildContext context) {
    return Scaffold(
      body: IndexedStack(
        index: _selectedIndex,
        children: const [
          HomePage(),
          MapNearbyPlacePage(),
          SearchKeywordPage(),
          MyPage(),
        ],
      ),
      bottomNavigationBar: CustomBottomNavigationBar(
        selectedIndex: _selectedIndex,
        onTabTapped: (int index) {
          setState(() {
            _selectedIndex = index;
          });
        },
      ),
    );
  }
}

하지만 한번에 모든 페이지가 렌더링 되면 안될수도 있고
위 코드로는 뒤로가기시 앱이 그대로 종료 되어버리는 문제가 발생한다.

PageView

페이지뷰의 특성대로 한번에 하나의 페이지만 렌더링 한다.
인덱스에 선태된 페이지만 렌더링 하므로 다른 페이지를 미리 렌더링 하지 않는다.

class _MainPageState extends State<MainPage> {
  final PageController _pageController = PageController();
  int _selectedIndex = 0;

  
  Widget build(BuildContext context) {
    return WillPopScope(
        onWillPop: () async {
          if (_selectedIndex != 0) {
            setState(() {
              _selectedIndex = 0;
              _pageController.jumpToPage(0);
            });
            return false;
          } else {
            final exit = await showDialog<bool>(
              context: context,
              builder: (context) => AlertDialog(
                content: const Text("앱을 종료하시겠습니까?"),
                actions: <Widget>[
                  TextButton(
                    onPressed: () => Navigator.pop(context, true),
                    child: const Text('확인'),
                  ),
                  TextButton(
                    onPressed: () => Navigator.pop(context, false),
                    child: const Text('취소'),
                  ),
                ],
              ),
            );

            // showDialog의 결과로부터 뒤로 가기 버튼의 동작을 결정합니다.
            return exit ?? false;
          }
        },
        child: Scaffold(
          body: PageView(
            controller: _pageController,
            physics: const NeverScrollableScrollPhysics(), // 스와이프 막아줌
            children: [
              const HomePage(),
              const MapNearbyPlacePage(),
              SearchKeywordPage(),
              const MyPage(),
            ],
          ),
          bottomNavigationBar: CustomBottomNavigationBar(
            selectedIndex: _selectedIndex,
            onTabTapped: (int index) {
              setState(() {
                _selectedIndex = index;

                _pageController.jumpToPage(index);
              });
            },
          ),
        ));
  }
}

WillPopScope

만약 지정한 인덱스에서 뒤로가기를 눌렀을 경우 원하는 위젯을 렌더링 할 수 있다.
위 코드 에서는 홈화면 ( 0 번 인덱스 ) 에서 뒤로가기를 눌렀을 경우에만 한번더 뒤로가기를 누르면 종료된다는 메세지를 표시 했다.
또한 홈화면이 아닐경우 홈화면으로 이동되도록 컨트롤러의 JumpToPage()를 이용했다.

profile
작은것부터

0개의 댓글