티스토리 뷰
Flutter에서는 Drawer 위젯을 통해 앱 내에서 손쉽게 네비게이션 기능을 구현할 수 있습니다. 특히, Material Design을 따르는 앱에서 Drawer는 화면 공간이 부족할 때 메뉴 옵션을 제공하는 매우 유용한 도구입니다. 이 블로그에서는 Flutter의 Drawer 위젯을 사용하는 방법에 대해 단계별로 설명하고, 이를 통해 어떻게 간단하고 직관적인 네비게이션 시스템을 구현할 수 있는지 살펴보겠습니다.
Scaffold로 기본 레이아웃 구성
Flutter에서 Drawer를 사용하려면 먼저 Scaffold 위젯으로 화면의 기본 구조를 설정해야 합니다. Scaffold는 Flutter에서 기본 레이아웃을 제공하는 컨테이너 역할을 하며, AppBar, Drawer, SnackBar 등의 Material Design 컴포넌트를 지원합니다.
아래는 Scaffold를 사용해 기본 구조를 만드는 코드 예시입니다:
Scaffold(
appBar: AppBar(
title: const Text('AppBar without hamburger button'),
),
drawer: // 다음 단계에서 Drawer를 추가합니다.
);
Drawer 추가하기
Scaffold에 Drawer를 추가하려면 drawer 속성에 Drawer 위젯을 설정하면 됩니다. Drawer는 일반적으로 메뉴나 네비게이션 항목을 포함한 사이드바로, Material Design의 가이드를 따르는 디자인을 제공합니다.
Scaffold(
appBar: AppBar(
title: const Text('AppBar with hamburger button'),
),
drawer: Drawer(
child: // 다음 단계에서 Drawer의 내용을 채웁니다.
),
);
Drawer에 항목 채우기
이제 Drawer에 사용할 콘텐츠를 추가할 차례입니다. ListView를 사용하여 여러 항목을 추가할 수 있으며, ListView는 스크롤이 가능하기 때문에 화면 공간이 부족해도 유동적으로 처리됩니다. 이 예시에서는 DrawerHeader와 두 개의 ListTile 항목을 추가합니다.
Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: [
const DrawerHeader(
decoration: BoxDecoration(
color: Colors.blue,
),
child: Text('Drawer Header'),
),
ListTile(
title: const Text('Item 1'),
onTap: () {
// 항목을 선택했을 때 상태를 업데이트합니다.
},
),
ListTile(
title: const Text('Item 2'),
onTap: () {
// 항목을 선택했을 때 상태를 업데이트합니다.
},
),
],
),
);
Drawer를 프로그램적으로 열기
보통 AppBar의 햄버거 버튼을 통해 Drawer를 열 수 있지만, 프로그램적으로 Drawer를 열고 싶을 때도 있습니다. 이를 위해 Scaffold.of(context).openDrawer()를 사용하여 Drawer를 열 수 있습니다.
Scaffold(
appBar: AppBar(
title: const Text('AppBar with hamburger button'),
leading: Builder(
builder: (context) {
return IconButton(
icon: const Icon(Icons.menu),
onPressed: () {
Scaffold.of(context).openDrawer();
},
);
},
),
),
drawer: Drawer(
child: // 앞서 정의한 Drawer 내용
),
);
Drawer를 프로그램적으로 닫기
사용자가 Drawer에서 항목을 선택한 후 자동으로 Drawer를 닫고 싶다면 Navigator.pop(context)를 호출하여 네비게이션 스택에서 Drawer를 제거할 수 있습니다.
ListTile(
title: const Text('Item 1'),
onTap: () {
// 상태 업데이트
// Drawer 닫기
Navigator.pop(context);
},
),
Drawer 활용 팁
- 다양한 콘텐츠 추가: Drawer에 단순히 텍스트만 추가하는 것이 아니라, 이미지, 아이콘 등 다양한 위젯을 배치하여 풍부한 사용자 경험을 제공할 수 있습니다.
- 상태 유지: Drawer는 여러 페이지에서 공통으로 사용되는 경우가 많으므로, 상태 관리를 통해 사용자가 Drawer를 사용해 다른 페이지로 이동하더라도 선택된 상태를 유지하는 것이 중요합니다.
- 적응형 디자인: 화면 크기에 맞게 적응형 Drawer를 설계하여, 모바일과 태블릿에서 모두 최적의 사용자 경험을 제공할 수 있도록 고려해야 합니다.
결론
Flutter의 Drawer 위젯은 간단한 코드로 직관적이고 유연한 네비게이션 시스템을 구축할 수 있는 강력한 도구입니다. 특히 Scaffold와 함께 사용할 때 매우 간결하게 앱 구조를 만들 수 있으며, 이를 통해 앱의 사용자 경험을 더욱 풍부하게 만들 수 있습니다. 간단한 UI이지만, 적절히 활용하면 복잡한 네비게이션 시스템도 쉽게 구현할 수 있습니다. 다양한 활용법을 시도해 보고 앱에 맞는 최적의 Drawer를 설계해 보세요.
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
static const appTitle = 'Drawer Demo';
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: appTitle,
home: MyHomePage(title: appTitle),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _selectedIndex = 0;
static const TextStyle optionStyle =
TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
static const List<Widget> _widgetOptions = <Widget>[
Text(
'Index 0: Home',
style: optionStyle,
),
Text(
'Index 1: Business',
style: optionStyle,
),
Text(
'Index 2: School',
style: optionStyle,
),
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
leading: Builder(
builder: (context) {
return IconButton(
icon: const Icon(Icons.menu),
onPressed: () {
Scaffold.of(context).openDrawer();
},
);
},
),
),
body: Center(
child: _widgetOptions[_selectedIndex],
),
drawer: Drawer(
// Add a ListView to the drawer. This ensures the user can scroll
// through the options in the drawer if there isn't enough vertical
// space to fit everything.
child: ListView(
// Important: Remove any padding from the ListView.
padding: EdgeInsets.zero,
children: [
const DrawerHeader(
decoration: BoxDecoration(
color: Colors.blue,
),
child: Text('Drawer Header'),
),
ListTile(
title: const Text('Home'),
selected: _selectedIndex == 0,
onTap: () {
// Update the state of the app
_onItemTapped(0);
// Then close the drawer
Navigator.pop(context);
},
),
ListTile(
title: const Text('Business'),
selected: _selectedIndex == 1,
onTap: () {
// Update the state of the app
_onItemTapped(1);
// Then close the drawer
Navigator.pop(context);
},
),
ListTile(
title: const Text('School'),
selected: _selectedIndex == 2,
onTap: () {
// Update the state of the app
_onItemTapped(2);
// Then close the drawer
Navigator.pop(context);
},
),
],
),
),
);
}
}
'Flutter Cookbook' 카테고리의 다른 글
패키지 폰트 사용 방법: 폰트 재사용을 위한 최적화된 접근 (5) | 2024.10.13 |
---|---|
SnackBar 구현하기: 사용자가 놓치지 않을 메시지를 전달하는 방법 (3) | 2024.10.12 |
Flutter에서 Opacity 애니메이션을 쉽게 구현하는 방법 (0) | 2024.10.10 |
Flutter의 애니메이션 기초: AnimatedContainer로 시작하는 간단한 애니메이션 구현 (5) | 2024.10.09 |
Flutter에서 물리 기반 애니메이션 구현하기: Physics Simulation 활용법 (2) | 2024.10.08 |