[Flutter] 12. Carrot App v1: Prototype

문정준's avatar
Jun 02, 2025
[Flutter] 12. Carrot App v1: Prototype
 

1. New Project

  • 이전 방식과 동일
 

2. Model 생성

  • 미리 사용할 아이콘 및 서버에서 받아올 데이터를 설정
  • 아래 파일을 lib/models 폴더 아래에 복사 후 붙여 넣어서 사용
 

3. 화면 캐싱

  • 화면 전환 시 Stack에 Screen 또는 Container를 화면에 보이도록 설정
    • Container를 출력시킴으로써 페이지를 이동할 때마다 모든 화면이 다시 rebuild 되는 것을 막음
    • 선택한 화면만 rebuild
Scaffold( body: IndexedStack( index: selectedIndex, children: [ loadPages.contains(0) ? HomeScreen() : Container(), loadPages.contains(1) ? NeighborhoodScreen() : Container(), loadPages.contains(2) ? NearMeScreen() : Container(), loadPages.contains(3) ? ChattingScreen() : Container(), loadPages.contains(4) ? MyCarrotScreen() : Container(), ], ), bottomNavigationBar: _bottomNavigationBar(context), );
 
  • 각 화면 예시 : 화면 설명만 작성
import 'package:flutter/material.dart'; class HomeScreen extends StatelessWidget { const HomeScreen(); @override Widget build(BuildContext context) { print("Home Screen build"); return Scaffold( body: Center(child: Text("Home Screen")), ); } }
 
  • const : 최초로 접속하는 화면만 메모리에 올려두고, 이후에 해당 페이지를 접속할 경우 메모리에 저장된 화면을 불러옴
    • Page의 Index를 선택 시 추가 (화면 저장용)
    • const로 설정되어 있기 때문에 화면 내부의 데이터를 변경할 수 없음
      • 변경이 필요할 시 StatefulWidget 필요 → 화면이 계속 새로 로딩되는 문제
class MainScreens extends StatefulWidget { @override State<MainScreens> createState() => _MainScreensState(); } class _MainScreensState extends State<MainScreens> { int selectedIndex = 0; List<int> loadPages = [0]; void selectBottomMenu(int index) { selectedIndex = index; if (!loadPages.contains(index)) loadPages.add(index); // 0 , 1 setState(() {}); } @override Widget build(BuildContext context) { return Scaffold( body: IndexedStack( index: selectedIndex, children: [ loadPages.contains(0) ? const HomeScreen() : Container(), loadPages.contains(1) ? const NeighborhoodScreen() : Container(), loadPages.contains(2) ? const NearMeScreen() : Container(), loadPages.contains(3) ? const ChattingScreen() : Container(), loadPages.contains(4) ? const MyCarrotScreen() : Container(), ], ), bottomNavigationBar: _bottomNavigationBar(context), ); } Theme _bottomNavigationBar(BuildContext context) { return BottomNavigationBar( /* // 지금 사용 안함 showSelectedLabels: true, showUnselectedLabels: false, */ type: BottomNavigationBarType.fixed, selectedItemColor: Colors.deepOrange, unselectedItemColor: Colors.black54, selectedFontSize: 12.0, unselectedFontSize: 12.0, currentIndex: selectedIndex, // 매개변수 자동 전달 onTap: selectBottomMenu, items: [ BottomNavigationBarItem(label: "홈", icon: Icon(CupertinoIcons.home)), BottomNavigationBarItem(label: "동네 생활", icon: Icon(CupertinoIcons.square_on_square)), BottomNavigationBarItem(label: "내 근처 정보", icon: Icon(Icons.location_on)), BottomNavigationBarItem(label: "채팅", icon: Icon(CupertinoIcons.chat_bubble_text)), BottomNavigationBarItem(label: "내 당근", icon: Icon(CupertinoIcons.person)), ], ), ); } }
 
  • initState() → 미리 List를 null로 build시킨 후 멤버로 추가
class MainScreens extends StatefulWidget { @override State<MainScreens> createState() => _MainScreensState(); } class _MainScreensState extends State<MainScreens> { int selectedIndex = 0; final List<Widget?> _screens = List.filled(5, null); @override void initState() { super.initState(); _screens[0] = HomeScreen(); // 처음은 미리 생성 } void selectBottomMenu(int index) { if (_screens[index] == null) { _screens[index] = _buildScreen(index); // 처음 클릭 시 생성 } setState(() { selectedIndex = index; }); } Widget _buildScreen(int index) { switch (index) { case 0: return HomeScreen(); case 1: return NeighborhoodLifeScreen(); case 2: return NearMeScreen(); case 3: return ChattingScreen(); case 4: return MyCarrotScreen(); default: return Container(); } } @override Widget build(BuildContext context) { return Scaffold( body: IndexedStack( index: selectedIndex, children: _screens.map((screen) => screen ?? Container()).toList(), ), bottomNavigationBar: _bottomNavigationBar(), ); } BottomNavigationBar _bottomNavigationBar() { return BottomNavigationBar( type: BottomNavigationBarType.fixed, selectedFontSize: 12.0, unselectedFontSize: 12.0, selectedItemColor: Colors.orange, unselectedItemColor: Colors.black54, currentIndex: selectedIndex, onTap: selectBottomMenu, items: const [ BottomNavigationBarItem(label: "홈", icon: Icon(CupertinoIcons.home)), BottomNavigationBarItem(label: "동네생활", icon: Icon(CupertinoIcons.square_on_square)), BottomNavigationBarItem(label: "내근처", icon: Icon(CupertinoIcons.placemark)), BottomNavigationBarItem(label: "채팅", icon: Icon(CupertinoIcons.chat_bubble_2)), BottomNavigationBarItem(label: "나의당근", icon: Icon(CupertinoIcons.person)), ], ); } }

CORS

  • Web으로 프로젝트를 실행할 경우, 그림이 보이지 않는 현상 발생
    • CORS 정책으로 인해 github 또는 외부의 주소로 그림을 받아 출력할 수 없음
    • Chrome으로 구동 시에는 이미지를 picsum 또는 asset에 저장하여 사용할 것
notion image
 
Share article

sxias