[Project] 2차 프로젝트 - 패키지 구조 만들고 로딩 알고리즘 만듬

김호정's avatar
Oct 22, 2024
[Project] 2차 프로젝트 - 패키지 구조 만들고 로딩 알고리즘 만듬
notion image
일단 바텀 네비게이션바의 홈은 탭바 를 갖고 있고, 각 탭바는 탭바 뷰를 갖고 있다.
이때 알아야 되는건, 탭바 뷰 는 Page 가 아니고 컴포넌트라고 생각해야 한다. 탭바가 움직일 때 모든 페이지가 랜더링 되는 것이 아니라 오렌지색인 내서재 에 해당하는 곳이 랜더링 되는 것이기 때문이다.
 

1. 기본 코드

class MainPage extends StatefulWidget { const MainPage({super.key}); @override State<MainPage> createState() => _MainPageState(); } class _MainPageState extends State<MainPage> with SingleTickerProviderStateMixin { late TabController controller; //탭의 컨트롤러 int _currentTab = 0; // 바텀네비바의 인덱스 // 각 탭의 제목 리스트 final List<String> titles = ['홈', '내서재', '검색', '설정']; @override void initState() { super.initState(); controller = TabController(length: 4, vsync: this); // 탭바를 정의한다. } @override void dispose() { super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( // AppBar의 title을 현재 선택된 탭의 제목으로 설정 appBar: CustomAppBar( titleText: titles[_currentTab], ), body: IndexedStack( index: _currentTab, children: [ // 하위 항목은 모두 bottomNavigationBar 의 인덱스 페이지 HomePage(), // 탭바를 갖고 있다. LibraryPage(), SearchPage(), SettingPage(), ], ), bottomNavigationBar: _bottomNavigation()); } }
_bottomNavigation 위젯 코드
BottomNavigationBar _bottomNavigation() { return BottomNavigationBar( selectedItemColor: Colors.blue, unselectedItemColor: Colors.black38, selectedFontSize: 10, unselectedFontSize: 10, type: BottomNavigationBarType.fixed, onTap: (index) { setState(() { _currentTab = index; }); }, //현재 선택된 index 지정 currentIndex: _currentTab, items: [ const BottomNavigationBarItem( label: '홈', icon: Icon(CupertinoIcons.house), ), const BottomNavigationBarItem( label: '내서재', icon: Icon(CupertinoIcons.book), ), const BottomNavigationBarItem( label: '검색', icon: Icon(CupertinoIcons.search), ), const BottomNavigationBarItem( label: '설정', icon: Icon(CupertinoIcons.settings), ), ], ); }
 
이때 큰 문제가 발생한다.
제일 처음 호출되는 MainPage 는 HomePage(), LibraryPage(), SearchPage(), SettingPage(), 를 갖고 있기 때문에 한번에 모든 페이지를 가져오려고 한다. (로딩이 100년 걸리게 된다.) 그렇기 때문에 필요한 페이지만 가져오는 알고리즘을 추가해야 한다.
 

2. 로딩 최적화

var loadPages = [0]; 를 추가한다. loadPages 는 현재 로딩 되어 진 페이지를 저장하는 곳이다. 기본적으로 home 을 갖고있게 되는데 (0번) 얘는 로딩시 처음 뜨는 곳이라 바로 넣어두었다.
 
children: [ loadPages.contains(0) ? const HomePage() : Container(), loadPages.contains(1) ? const LibraryPage() : Container(), loadPages.contains(2) ? const SearchPage() : Container(), loadPages.contains(3) ? const SettingPage() : Container(), ],
배열에 해당 인덱스가 들어있다면 페이지를 랜더링 하고, 아닐 시 빈 Container 를 만든다.
이후 탭을 눌렀을 때 배열에 인덱스를 추가하여 랜더링 할 수 있도록 하고, const 를 사용하여 이미 랜더링 되었던 화면은 다시 그리지 않도록 하였다.
 
notion image
 

전체코드

import 'package:bookbox/ui/components/custom_app_bar.dart'; import 'package:bookbox/ui/main/home/home_page.dart'; import 'package:bookbox/ui/main/library/library_page.dart'; import 'package:bookbox/ui/main/search/search_page.dart'; import 'package:bookbox/ui/main/setting/setting_page.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; class MainPage extends StatefulWidget { const MainPage({super.key}); @override State<MainPage> createState() => _MainPageState(); } class _MainPageState extends State<MainPage> with SingleTickerProviderStateMixin { late TabController controller; int _currentTab = 0; var loadPages = [0]; //저장되는 곳 // 각 탭의 제목 리스트 final List<String> titles = ['홈', '내서재', '검색', '설정']; @override void initState() { super.initState(); controller = TabController(length: 4, vsync: this); } @override void dispose() { super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( // AppBar의 title을 현재 선택된 탭의 제목으로 설정 appBar: CustomAppBar( titleText: titles[_currentTab], ), //titleText: titles[index], body: IndexedStack( index: _currentTab, children: [ loadPages.contains(0) ? const HomePage() : Container(), loadPages.contains(1) ? const LibraryPage() : Container(), loadPages.contains(2) ? const SearchPage() : Container(), loadPages.contains(3) ? const SettingPage() : Container(), ], ), bottomNavigationBar: _bottomNavigation()); } BottomNavigationBar _bottomNavigation() { return BottomNavigationBar( selectedItemColor: Colors.blue, unselectedItemColor: Colors.black38, selectedFontSize: 10, unselectedFontSize: 10, type: BottomNavigationBarType.fixed, currentIndex: _currentTab, onTap: (index) { var pages = loadPages; if (!pages.contains(index)) { pages.add(index); print(pages); } _currentTab = index; loadPages = pages; setState(() {}); }, //현재 선택된 index 지정 items: [ const BottomNavigationBarItem( label: '홈', icon: Icon(CupertinoIcons.house), ), const BottomNavigationBarItem( label: '내서재', icon: Icon(CupertinoIcons.book), ), const BottomNavigationBarItem( label: '검색', icon: Icon(CupertinoIcons.search), ), const BottomNavigationBarItem( label: '설정', icon: Icon(CupertinoIcons.settings), ), ], ); } }
 

패키지

notion image
notion image
패키지는 각 페이지이고, 패키지 내부에 탭을 위한 패키지를 생성했다. 이제 내부 요소를 만들면 된다.
Share article

keepgoing