본문 바로가기
flutter/Widget of the Week

Flutter[플러터] / Drawer 를 사용하여 측면 메뉴 패널 만들기 (드로월, tool bar, navigation, 왼쪽 액션바, 시트, sheet, 탐색 툴바) Drawer (Flutter Widget of the Week)

by ch5c 2025. 6. 24.
반응형

Drawer class

애플리케이션의 탐색 링크를 표시하기 위해 Scaffold 의 가장자리에서 수평으로 슬라이드 되는 Material Design 패널입니다.

이 구성 요소에는 NavigationDrawer 라는 Material 3 버전이 있는데 , 이는 Material 3에 맞게 구성된 애플리케이션에 더 적합합니다( ThemeData.useMaterial3 참조 ).

https://youtu.be/WRj86iHihgY

공식 문서 코드

 

 


페이지가 많아지고 기능이 많아지는데 그것을 공통화면에서 그 페이지들로 넘어가게 하려면 가장 좋은 방법은 무엇일까? 당연하게도 메뉴를 제작하여 메뉴에서 이동하게 만드는 것이다. 그 메뉴는 상단에 위치해 있는 앱 바가 될 수도 있고 하단에 위치해 있는 내비게이션바가 될 수도 있다. 하지만 이번에 알아볼 것은 흔히들 사용하는 형식이다. 메뉴버튼을 누르면 메뉴버튼이 위치해 있는 곳에서 패널이 튀어나와서 원하는 페이지로 이동할 수 있게 도와준다. 이러한 메뉴 패널을 아주 쉽게 만들어주는 위젯이 바로 Drawer 위젯이다.

이 Drawer 위젯은 앱의 측면에 위치하는 내비게이션 메뉴 패널을 구현할 때 사용된다. 일반적으로 앱의 왼쪽(또는 오른쪽)에 슬라이딩 방식으로 열리고, 다양한 메뉴 항목들을 포함해 사용자가 앱의 다른 페이지로 이동할 수 있도록 한다. 바로 알아보자.

하위 속성
속성명 타입 기본값 설명
backgroundColor Color? null Drawer의 배경색을 설정
elevation double? 16.0 그림자 깊이를 설정해 z축에서의 높이를 지정
shadowColor Color? null 그림자 색상을 설정
surfaceTintColor Color? Colors.transparent 배경색에 겹쳐지는 표면 틴트 색상
shape ShapeBorder? null Drawer의 테두리 모양을 정의
width double? 304.0 Drawer의 너비를 설정
child Widget? null Drawer 내부에 표시할 콘텐츠
semanticLabel String? MaterialLocalizations.drawerLabel 접근성 기술에서 Drawer를 설명하는 라벨
clipBehavior Clip? Clip.none 또는 Clip.hardEdge shape이 있을 때 잘리는 방식 지정

 

일단 이 위젯은 사용하기 정말 간단하다. 놀랍게도 Scaffold 안에 그냥 이거 쓰라고 전용 파라미터가 구비되어 있다 ㄷㄷ

Scaffold(
  drawer: Drawer(),
)

이미 이렇게만 해줘도 메뉴 패널 생성은 끝났다.

기본은 왼쪽이지만 오른쪽에서도 나오게 하고 싶으면 그냥 endDrawer 속성을 사용해 주면 된다.

Scaffold(
  endDrawer: Drawer(),
)

또한 drawer 혹은 endDrawer 파라미터를 사용 시 기본적으로 AppBar 위젯을 사용하면 그 위치에 맞게 메뉴 아이콘이 생성이 되어 있다. 그리고 그러한 메뉴 아이콘을 클릭하면 메뉴 패널이 나오게 된다.

Scaffold(
  appBar: AppBar(),
  drawer: Drawer(),
  endDrawer: Drawer(),
)

위 코드 실행시 AppBar 의 상태

그냥 화면을 스와이프 해서 메뉴 패널이 나오면 좋겠지만 안탑깝게 도 그러한 기능은 없다.

여기서 주의해야 할 점은 Drawer 은 오직 최상위 Scaffold 안에서만 거의 동작하기 때문에 위젯 안에 Drawer 를 배치하고 싶다고 Scaffold 를 또 배치해서 넣는다고 해도 동작하지 않는다.

암튼 그렇다면 이 패널을 여는 방법은 또 뭐가 있을까? 가장 보편적인 방법으로는 글로벌 키를 사용하여 Scaffold 의 context 를 받아와 여는 방법이 있다.

먼저 사용할 key, 글로벌 키를 만들어준다.

final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();

이제 이 키를 Scaffold 에 넣어준다.

Scaffold(
  key: _scaffoldKey,

이렇게 key 를 넣어줬다면 이제 사용가능해지게 되는데 원래 Drawer 을 여는 코드 자체는 아래와 같다.

Scaffold.of(context).openDrawer();

(영상을 보면 이렇게 사용하라고 나와있는데 실상 예제 코드를 보면 그냥 글로벌 키를 사용하는 모순적인 모습을 볼 수 있다.)

저 코드도 맞아 보이지만 동작하지 않는 원인이 있다. 바로 Scaffold.of(context)가 실행되는 시점의 context가 Scaffold 내부에 직접 연결되지 않았기 때문이다. 즉 Scaffold 의 context 를 가져오지 못하여서 실행해 보면 아무 동작도 하지 않는다.

암튼 위 코드에서 가져올 건 openDrawer 함수 밖에 없겠다. 오른쪽에서 열리게 해놨다면 openEndDrawer 쓰면 된다.

onPressed: () {
  _scaffoldKey.currentState!.openDrawer();
},

이 코드는 현재 scaffoldKey 를 가져오고 있는데 아까 위에서 만들었다시피 GlobalKey<ScaffoldState> 이런 타입을 가지고 있다.

이건 Scaffold 의 상태에 접근하기 위하여 사용되는 키인데 이걸로 일단 Scaffold 에 접근한 후 currentState 로 위젯에 연결된 상태 객체(ScaffoldState)를 가져오게 된다.

이제 마지막으로 상태 다 가져왔으니까 openDrawer 하면 잘 패널이 열리게 될 것이다.

여기까지 Drawer 위젯의 사용법이었다. 그렇다면 이제 안을 어떻게 꾸밀지 알아보자.

Drawer 은 하위 속성, 파라미터로 child 를 갖고 있는데 보통은 여기다가 ListView 를 사용하여 배치한다.

drawer: Drawer(
  child: ListView(
    children: [
      DrawerHeader(child: Text('타이틀')),
      ListTile(title: Text('타일1'),),
      ListTile(title: Text('타일2'),),
      ListTile(title: Text('타일3'),),
    ],
  ),
),

보통은 이런 식으로 사용하게 된다. ListView 안에 ListTile 들로 아이템을 배치해 주고 제목 같은 건 DrawerHeader 를 사용하여 머테리얼 디자인에 맞게 배치해 줄 수 있다.

이제 여기서 더 파라미터를 알아보자면

backgroundColor: Colors.blue,

backroundColor 를 사용해서 배경색을 바로 먹여줄 수 있다.

사실 근데 나는 child 안에다가 Column 배치한 다음에 커스텀으로 디자인할 거 같긴 하다.

 

암튼 이렇게 Drawer 위젯에 대해서 간단하게 알아보았다. 이 위젯은 이런 되게 좋은 기능인데 반해 사용하기 진짜 엄청 쉬우니까 꼭 사용해 보길 바란다. 도움이 되었길 바라며 마치겠다.

 

반응형