[003] 플러터 (Flutter) Tip - Scaffold, Appbar, Drawer, BottomNavigationBar, Routing (3페이지 구현 실습)

2023. 5. 21. 21:04모바일어플개발/Flutter Tips

반응형

안녕하세요~ totally 개발자입니다.

 

아래처럼 Home, Search, Settings 페이지를 구성하고 Home이 아닌 Search와 Settings에서는 좌측 상단의 drawer 메뉴를 보이지 않게 하고 하단 메뉴의 아이콘을 클릭하면 각 페이지로 이동할 수 있는 간단한 실습을 해보도록 하겠습니다.

 

Step 1: 시작하기에 앞서 구현 방법은 여러 가지로 꼭 해당 방법으로 구현하실 필요는 없으시고 라우팅 방법도 필자처럼 하실 수도 있고 Navigator.push, pop 등을 활용해서 하실 수도 있는 등 구현 상황에 따라 다르게 적용하셔야 함을 미리 말씀을 드립니다. 먼저 아래처럼 5개의 파일들을 구성합니다.

 

 

Step 2: routeObserver를 구성을 해줍니다. 다만 이 실습에서는 이 override 부분을 사용하지는 않습니다만 추후 필요를 위해 작성을 해줍시다. didPush는 기존 화면에 새 화면을 얹어서 새 화면을 보이게 하는 방법, didReplace는 기존 화면을 새 화면으로 대체하는 방법, didPop은 현재 화면을 빼서 기존 화면으로 돌아가는 방법입니다. 다만 이 실습에서는 currentRoute만 사용하여 달리 적용하도록 하겠습니다.

 

import 'package:flutter/material.dart';
class AppRouteObserver extends RouteObserver<PageRoute<dynamic>> {
String currentRoute = '';
@override
void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {
super.didPush(route, previousRoute);
currentRoute = route.settings.name!;
}
@override
void didReplace({Route<dynamic>? newRoute, Route<dynamic>? oldRoute}) {
super.didReplace(newRoute: newRoute, oldRoute: oldRoute);
if (newRoute != null) {
currentRoute = newRoute.settings.name!;
}
}
@override
void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) {
super.didPop(route, previousRoute);
currentRoute = previousRoute?.settings.name ?? '';
}
}

 

Step 3: homePage.dart, searchPage.dart, settingPage.dart를 구성합니다.

 

import 'package:flutter/material.dart';
import 'package:project/main.dart';
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return const Center(
child: Text("HOME PAGE"),
);
}
}
view raw HomePage.dart hosted with ❤ by GitHub

 

import 'package:flutter/material.dart';
class SearchPage extends StatefulWidget {
const SearchPage({super.key});
@override
State<SearchPage> createState() => _SearchPageState();
}
class _SearchPageState extends State<SearchPage> {
@override
Widget build(BuildContext context) {
return const Center(
child: Text("SEARCH PAGE"),
);
}
}
view raw searchPage.dart hosted with ❤ by GitHub

 

import 'package:flutter/material.dart';
class SettingPage extends StatefulWidget {
const SettingPage({super.key});
@override
State<SettingPage> createState() => _SettingPageState();
}
class _SettingPageState extends State<SettingPage> {
@override
Widget build(BuildContext context) {
return const Center(child: Text("SETTING PAGE"));
}
}

 

Step 4: main.dart를 작성합니다. AppRouteObserver의 인스턴스를 만들어주시고 (7번째 줄), 그 다음 22-24번째 줄에 routes 객체를 명시해줍니다.

 

 

Step 5: MainPage 클래스를 작성하시고 _selectedIndex 변수를 선언합니다. (탭 이동할 때 인덱스 체크 역할)

 

 

Step 6: 46번째에 현재 루트가 Home인 경우에만 Drawer 메뉴를 보이게 하고 싶으시면 ? : Ternary(삼항) 연산자를 활용하면 됩니다. 예를 들어 1 +2  == 3 ? true : false 인 방식입니다. 즉 null로 값을 주면 보이지 않는 효과를 연출할 수 있습니다. 

 

 

Step 7: 하단 네비게이션 바 부분입니다. 66, 73, 80번째에 changeRoute 부분 함수를 호출하는데 이 부분은 아래에 작성했습니다.

 

위처럼 body 부분에 현재 루트를 체크하여 나타낼 수 있고 Navigator를 사용하여 구현할 수도 있습니다. 저는 3페이지로 비교적 간단하기 때문에 이렇게 구성했습니다. 94-102번째 줄에 changeRoute 함수로 route를 전달하시고 루트를 체크 후 _selectedIndex를 업데이트한 뒤 setState로 상태 업데이트를 해주시면 완료입니다. 그 결과는 아래와 같습니다.

 

 

[main.dart 코드]

 

import 'package:flutter/material.dart';
import 'package:project/RouteObserver.dart';
import 'package:project/homePage.dart';
import 'package:project/searchPage.dart';
import 'package:project/settingPage.dart';
AppRouteObserver routeObserver = AppRouteObserver();
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter App',
navigatorObservers: [routeObserver],
routes: {
'/': (context) => const MainPage(),
'/search': (context) => const SearchPage(),
'/settings': (context) => const SettingPage(),
},
);
}
}
class MainPage extends StatefulWidget {
const MainPage({Key? key}) : super(key: key);
@override
State<MainPage> createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
int _selectedIndex = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('My App'),
),
drawer: routeObserver.currentRoute == '/'
? Drawer(
child: ListView(
children: [
ListTile(
onTap: () => routeObserver.currentRoute = '/',
title: const Text("Home"),
),
],
),
)
: null,
bottomNavigationBar: BottomNavigationBar(
selectedItemColor: Colors.blue,
unselectedItemColor: Colors.black,
currentIndex: _selectedIndex,
items: [
BottomNavigationBarItem(
label: "Home",
icon: IconButton(
onPressed: () => changeRoute('/'),
icon: const Icon(Icons.home),
),
),
BottomNavigationBarItem(
label: "Search",
icon: IconButton(
onPressed: () => changeRoute('/search'),
icon: const Icon(Icons.search),
),
),
BottomNavigationBarItem(
label: "Settings",
icon: IconButton(
onPressed: () => changeRoute('/setting'),
icon: const Icon(Icons.settings),
),
),
],
),
body: routeObserver.currentRoute == '/'
? const HomePage()
: routeObserver.currentRoute == '/search'
? const SearchPage()
: const SettingPage(),
);
}
void changeRoute(String route) {
routeObserver.currentRoute = route;
_selectedIndex = route == '/'
? 0
: route == '/search'
? 1
: 2;
setState(() {});
}
}
view raw main.dart hosted with ❤ by GitHub

 

반응형