flutter를 이용하여 앱을 개발할 때 페이지 간 이동 시 유용하게 사용할 수 있는 기능 중에 navigation drawer 기능이 있습니다. 이번 글에서는 flutter navigation drawer의 사용 방법에 대해서 알아보도록 하겠습니다.
Table of Contents
navigation drawer를 만들기 위해서는 Scaffold 위젯을 이용해야 하며, drawer라는 프로퍼티를 설정해 주어야 합니다. NavigationDrawer라는 이름의 클래스를 별도로 생성한 뒤 Drawer를 리턴합니다.
이를 실행하면 다음과 같이 화면 좌측에 빈 drawer가 생성되는 것을 볼 수 있습니다.
Drawer 위젯 내부에 메뉴가 많아질 때 스크롤이 생길 수 있도록 SingleChildScrollView 위젯을 만들고 그 안에 Column을 생성한 뒤 buildHeader와 buildMenuItems 위젯을 정의해 줍니다.
buildHeader 위젯의 경우 사용하는 핸드폰의 작업표시줄로 인한 안보임 현상을 방지하기 위해서 padding을 설정해 줍니다. 그리고 buildMenuItems는 ListTile을 이용하여 각 페이지로 이동할 수 있는 버튼을 만들어줍니다.
메뉴 버튼간의 간격을 조정하기 위해서 Wrap 위젯의 runSpacing 프로퍼티를 이용합니다. 또한 Wrap 위젯을 Container 위젯으로 감싼 뒤 padding 프로퍼티를 이용해서 추가적인 여백 조절을 할 수 있습니다.
메뉴 별 페이지 이동하기
다음으로 Navigation Drawer의 메뉴를 클릭할 시에 페이지 이동에 대해서 설명하도록 하겠습니다. 페이지 이동을 위해서는 ListTile 위젯의 onTap 프로퍼티를 설정하면 되는데 pushReplacement와 push 메서드를 이용합니다.
Navigator.of(context).pushReplacement
pushReplacement 메서드를 이용할 경우 아이콘을 클릭 시 해당 페이지로 전환되며 Navigation Drawer를 바로 이용할 수 있도록 메뉴 아이콘이 그대로 유지됩니다.
Navigator.of(context).push
push 메서드의 경우 홈페이지로 이동하는 기능은 동일하나 홈페이지로 이동한 이후 페이지에 Navigation Drawer 아이콘이 생기는 것이 아니라 Back 버튼이 생성됩니다. 페이지를 쌓는 구조이기 때문에 Back 버튼을 클릭할 경우 이전 페이지로 돌아가게 됩니다.
Header
Header 부분을 별도로 구분하여 CircleAvatar와 Text 위젯을 이용하여 내용을 입력하였습니다.
InkWell 위젯을 기존의 BuildHeader내 Container 상위에 적용한 뒤 onTap 프로퍼티를 적용하여 클릭 시 별도의 페이지로 이동할 수 있도록 설정할 수 있습니다.
완성 소스 코드
완성된 소스코드를 공유드리도록 하겠습니다.
import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar( title: const Text("home"), backgroundColor: Colors.deepPurple, ), drawer: const NavigationDrawer(), ), ); } } class NavigationDrawer extends StatelessWidget { const NavigationDrawer({super.key}); @override Widget build(BuildContext context) { return Drawer( child: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ buildHeader(context), buildMenuItems(context), ], ))); } Widget buildHeader(BuildContext context) { return InkWell( onTap: () { Navigator.pop(context); Navigator.of(context).push( MaterialPageRoute( builder: (context) { return const UserPage(); }, ), ); }, child: Container( color: Colors.deepPurple, padding: EdgeInsets.only( top: 24 + MediaQuery.of(context).padding.top, bottom: 24, ), child: const Column( children: [ CircleAvatar( radius: 52, backgroundColor: Colors.deepPurple, backgroundImage: NetworkImage( 'https://static.vecteezy.com/system/resources/previews/001/191/986/original/circle-logo-png.png'), ), SizedBox(height: 24), Text( 'Jabhak-Dasik', style: TextStyle(fontSize: 28, color: Colors.white), ), Text( 'talkaboutme86@gmail.com', style: TextStyle(fontSize: 16, color: Colors.white), ), ], ), ), ); } Widget buildMenuItems(BuildContext context) { return Container( padding: const EdgeInsets.all(24), child: Wrap( runSpacing: 16, children: [ ListTile( leading: const Icon(Icons.home_outlined), title: const Text('Home'), onTap: () { Navigator.of(context).pushReplacement( MaterialPageRoute( builder: ((context) => const MyApp()), ), ); }, ), ListTile( leading: const Icon(Icons.favorite_border), title: const Text('Favorites'), onTap: () { // close navigation drawer before Navigator.pop(context); Navigator.of(context).push( MaterialPageRoute( builder: ((context) => const FavoritesPage()), ), ); }, ), ListTile( leading: const Icon(Icons.update), title: const Text('Updates'), onTap: () {}, ), ListTile( leading: const Icon(Icons.account_tree_outlined), title: const Text('Plugins'), onTap: () {}, ), ], ), ); } } class FavoritesPage extends StatelessWidget { const FavoritesPage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Favourites Page'), backgroundColor: Colors.green, ), ); } } class UserPage extends StatelessWidget { const UserPage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("User Page"), ), body: const Column( children: [Text('This is User Page')], ), ); } }