
Pada tutorial kali ini kita akan membahas tentang cara membuat hidden drawer di flutter. Untuk membuat hidden drawer kita dalam melakukan dengan dua cara berbeda yaitu menggunakan library hidden_drawer_menu dan tanpa library alias membuatnya dari nol.
Namun sebelum membuat hidden drawer, bagi kamu yang belum memahami tentang navigation drawer silahkan baca tutorialnya disini
Berikut langkah-langkah membuat hidden drawer di flutter :
Daftar Isi
Package url : https://pub.dev/packages/hidden_drawer_menu
1. Install package hidden_drawer_menu dengan cara menambahkannya pada list dependencies di pubspec.yaml
dependencies:
hidden_drawer_menu: ^2.0.1
2. Import package
import 'package:hidden_drawer_menu/hidden_drawer_menu.dart';
3. Buat list dengan ScreenHiddenDrawer, lalu pada initState tambahkan list item dengan ItemHiddenMenu widget
...
class _MyApp extends State<MyApp> {
List<ScreenHiddenDrawer> items = List();
@override
void initState() {
items.add(
new ScreenHiddenDrawer(
new ItemHiddenMenu(
name: "Home",
),
HomeScreen(),
),
);
...
4. Pada properti home gunakan widget HiddenDrawerMenu dan pada properti screens gunakan list yang telah kita buat tadi
...
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: HiddenDrawerMenu(
initPositionSelected: 0,
screens: items,
...
Kode lengkapnya menjadi seperti dibawah ini
main.dart
import 'package:flutter/material.dart'; import 'package:hidden_drawer_menu/hidden_drawer_menu.dart'; main() => runApp(MyApp()); class MyApp extends StatefulWidget { @override State<StatefulWidget> createState() { return _MyApp(); } } class _MyApp extends State<MyApp> { // Buat list ScreenHiddenDrawer List<ScreenHiddenDrawer> items = List(); // Add items di init() method @override void initState() { items.add(new ScreenHiddenDrawer( new ItemHiddenMenu( name: "Home", baseStyle: TextStyle(color: Colors.white.withOpacity(0.8), fontSize: 28.0), colorLineSelected: Colors.teal, ), HomeScreen())); items.add(new ScreenHiddenDrawer( new ItemHiddenMenu( name: "Gallery", baseStyle: TextStyle(color: Colors.white.withOpacity(0.8), fontSize: 28.0), colorLineSelected: Colors.orange, ), GalleryScreen())); super.initState(); } @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, home: HiddenDrawerMenu( initPositionSelected: 0, screens: items, contentCornerRadius: 30.0, backgroundColorMenu: Colors.cyan, backgroundMenu: DecorationImage( image: NetworkImage( 'https://cdn.pixabay.com/photo/2017/08/07/21/52/nature-2608274_1280.jpg', ), fit: BoxFit.cover), // typeOpen: TypeOpen.FROM_RIGHT, // enableScaleAnimin: true, // enableCornerAnimin: true, // slidePercent: 80.0, // verticalScalePercent: 80.0, // iconMenuAppBar: Icon(Icons.menu), // backgroundContent: DecorationImage((image: ExactAssetImage('assets/bg_news.jpg'),fit: BoxFit.cover), // whithAutoTittleName: true, // styleAutoTittleName: TextStyle(color: Colors.red), // actionsAppBar: <Widget>[], // backgroundColorContent: Colors.blue, // backgroundColorAppBar: Colors.blue, // elevationAppBar: 1.0, // tittleAppBar: Center(child: Icon(Icons.ac_unit),), // enableShadowItensMenu: true, ), ); } } class HomeScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Container( child: Center( child: Column( mainAxisSize: MainAxisSize.min, children: <Widget>[ Text( "Home Screen", style: TextStyle(fontSize: 30.0), ), ], ), ), ); } } class GalleryScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Container( child: Center( child: Column( mainAxisSize: MainAxisSize.min, children: <Widget>[ Text( "Gallery Screen", style: TextStyle(fontSize: 30.0), ), RaisedButton( child: Text('Buka Menu'), onPressed: () { SimpleHiddenDrawerController.of(context).toggle(); }, ) ], ), ), ); } }
Hasil kode diatas akan seperti gambar dibawah ini

Kelebihan menggunakan library hidden_drawer_menu ini yaitu membuat hidden drawer jadi sangat mudah dan simple. Namun kekurangannya memiliki keterbatasan dalam mengubah tampilannya menu.
Tanpa Bantuan Package (Disarankan)
Untuk membuat hidden drawer di flutter tanpa bantuan package, kita akan membagi menjadi empat (4) files seperti dibawah ini
Struktur file
── lib
│ ├── drawerController.dart
│ ├── drawerMenu.dart
│ ├── main.dart
│ └── screen.dart
Langkah-langkah
1. Pertama kita buat projek flutter baru, atau jika ingin menggunakan projek yang sudah ada silahkan skip saja tahapan ini
$ flutter create belajar_flutter
2. Buat file baru bernama screen.dart yang isinya seperti ini
screen.dart
import 'package:flutter/material.dart'; class Home extends StatelessWidget { @override Widget build(BuildContext context) { return Center( child: Column(mainAxisAlignment: MainAxisAlignment.center, // crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( 'Tutorial Membuat Hidden Drawer', style: (TextStyle(fontSize: 20)), ), Text('BelajarFlutter.com'), ]), ); } }
3. Selanjutnya buat drawer Controller yang berfungsi untuk mengatur fungsi buka tutup menu serta animasinya. Untuk file controller ini kita bernama drawerController.dart.
Hidden Drawer sebenarnya merupakan Stack widget dimana menumpukan tampilan main screen dengan menu
drawerController.dart
import 'package:flutter/material.dart'; class HiddenDrawerController { HiddenDrawerController({this.items, @required DrawerContent initialPage}) { this.page = initialPage; } List<DrawerItem> items; Function open; Function close; DrawerContent page; } class DrawerContent extends StatefulWidget { Function onMenuPressed; State<StatefulWidget> createState() { return null; } } class DrawerItem extends StatelessWidget { DrawerItem({this.onPressed, this.icon, this.text, this.page}); Function onPressed; Widget icon; Widget text; DrawerContent page; @override Widget build(BuildContext context) { return Container( child: Material( color: Colors.transparent, child: InkWell( onTap: onPressed, child: Padding( padding: EdgeInsets.symmetric(vertical: 12.0), child: Row( children: <Widget>[ Container( padding: EdgeInsets.only(left: 16, right: 8), child: icon, ), text ], ), ), ), ), ); } } class HiddenDrawer extends StatefulWidget { HiddenDrawer({this.header, this.decoration, this.controller}); BoxDecoration decoration; Widget header; HiddenDrawerController controller; @override _HiddenDrawerState createState() => _HiddenDrawerState(); } class _HiddenDrawerState extends State<HiddenDrawer> with TickerProviderStateMixin { bool isMenuOpen = false; bool isMenudragging = false; Animation<double> animation, scaleAnimation; Animation<BorderRadius> radiusAnimation; AnimationController animationController; @override void initState() { super.initState(); animationController = AnimationController(vsync: this, duration: Duration(microseconds: 300)); animation = Tween<double>(begin: 0.0, end: 1.0).animate(animationController) ..addListener(() { setState(() {}); }); scaleAnimation = Tween<double>(begin: 1.0, end: 0.86).animate(animationController); radiusAnimation = BorderRadiusTween( begin: BorderRadius.circular(0.0), end: BorderRadius.circular(32)) .animate( CurvedAnimation(parent: animationController, curve: Curves.ease)); } @override void dispose() { super.dispose(); animationController.dispose(); } drawerItems() { return widget.controller.items.map((DrawerItem item) { if (item.onPressed == null) { item.onPressed = () { widget.controller.page = item.page; widget.controller.close(); }; } item.page.onMenuPressed = menuPress; return item; }).toList(); } menuPress() { isMenuOpen ? closeDrawer() : openDrawer(); } closeDrawer() { animationController.reverse(); setState(() { isMenuOpen = false; }); } openDrawer() { animationController.forward(); setState(() { isMenuOpen = true; }); } animations() { if (isMenudragging) { var opened = false; setState(() { isMenudragging = false; }); if (animationController.value >= 0.4) { animationController.forward(); opened = true; } else { animationController.reverse(); } setState(() { isMenuOpen = opened; }); } } @override Widget build(BuildContext context) { widget.controller.page.onMenuPressed = menuPress; widget.controller.close = closeDrawer; widget.controller.open = openDrawer; return Listener( onPointerDown: (PointerDownEvent event) { if (isMenuOpen && event.position.dx / MediaQuery.of(context).size.width >= 0.66) { closeDrawer(); } else { setState(() { isMenudragging = (!isMenudragging && event.position.dx <= 8.0); }); } }, onPointerMove: (PointerMoveEvent event) { if (isMenudragging) { animationController.value = event.position.dx / MediaQuery.of(context).size.width; } }, onPointerUp: (PointerUpEvent event) { animations(); }, onPointerCancel: (PointerCancelEvent event) { animations(); }, child: Stack( children: <Widget>[ Container( decoration: widget.decoration, child: ListView( children: <Widget>[ Container( margin: EdgeInsets.all(20), child: widget.header, ), SizedBox( height: 20, ), Column(children: drawerItems()) ], ), ), Transform.scale( scale: scaleAnimation.value, child: Transform.translate( offset: Offset( MediaQuery.of(context).size.width * 0.66 * animation.value, 0.0), child: AbsorbPointer( absorbing: isMenuOpen, child: Stack( children: <Widget>[ Column( children: <Widget>[ Expanded( child: Container( child: ClipRRect( borderRadius: BorderRadius.all(Radius.circular(44)), child: Container( color: Colors.white.withOpacity(0.2), ), ), ), ) ], ), Padding( padding: EdgeInsets.only(left: animation.value * 4), child: ClipRRect( borderRadius: radiusAnimation.value, child: Container( color: Colors.white, child: widget.controller.page, ), ), ) ], ), )), ) ], ), ); } }
4. Setelah itu saatnya membuat widget untuk tampilan menunya. Dalam file ini bertujuan untuk menambahkan menu item atau mendesign tampilan sesuai kebutuhan aplikasi. File nya kita namakan drawerMenu.dart
drawerMenu.dart
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'screen.dart'; import 'drawerController.dart'; class MenuPage extends DrawerContent { MenuPage({Key key, this.title}); final String title; @override _MenuState createState() => _MenuState(); } class _MenuState extends State<MenuPage> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( leading: new IconButton( icon: new Icon(Icons.dehaze), onPressed: () => {widget.onMenuPressed()}, ), title: Text('Belajar Hidden Drawer'), ), body: Home(), ); } } class MainWidget extends StatefulWidget { MainWidget({Key key, this.title}) : super(key: key); final String title; @override _MainWidgetState createState() => _MainWidgetState(); } class _MainWidgetState extends State<MainWidget> with TickerProviderStateMixin { HiddenDrawerController _drawerController; @override void initState() { super.initState(); _drawerController = HiddenDrawerController( initialPage: MenuPage( title: 'main', ), items: [ DrawerItem( text: Text( 'Home', style: TextStyle(color: Colors.white), ), icon: Icon(Icons.home, color: Colors.white), page: MenuPage( title: 'Home', ), ), DrawerItem( text: Text( 'Gallery', style: TextStyle(color: Colors.white), ), icon: Icon(Icons.photo_album, color: Colors.white), page: MenuPage( title: 'Gallery', ), ), DrawerItem( text: Text( 'Favorites', style: TextStyle(color: Colors.white), ), icon: Icon(Icons.favorite, color: Colors.white), page: MenuPage( title: 'Favorites', ), ), DrawerItem( text: Text( 'Settings', style: TextStyle(color: Colors.white), ), icon: Icon(Icons.settings, color: Colors.white), page: MenuPage( title: 'Settings', ), ) ]); } @override Widget build(BuildContext context) { return Scaffold( body: HiddenDrawer( controller: _drawerController, header: Align( alignment: Alignment.topLeft, child: Column(children: <Widget>[ Container( decoration: BoxDecoration( shape: BoxShape.circle, border: Border.all(color: Colors.black.withOpacity(0.1), width: 1), ), padding: EdgeInsets.symmetric(horizontal: 16.0), width: MediaQuery.of(context).size.width * 0.4, child: ClipOval( child: Image( fit: BoxFit.fill, image: NetworkImage( 'https://cdn.pixabay.com/photo/2014/11/30/14/11/kitty-551554_1280.jpg', ), ), ), ), SizedBox( height: 6, ), Text( 'Hallo Meong', style: TextStyle( color: Colors.white, fontSize: 20, fontWeight: FontWeight.bold), ), Padding( padding: const EdgeInsets.only(top: 8.0, left: 0), child: Text( 'belajarflutter.com', style: TextStyle(color: Colors.white, fontSize: 14), ), ) ]), ), decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ Colors.deepPurpleAccent.withOpacity(0.5), Colors.cyan, Colors.teal ]), ), ), ); } }
5. Dan terakhir, pada main.dart import drawerMenu ke home properti. Kurang lebih code nya seperti dibawah ini
main.dart
import 'package:flutter/material.dart'; import 'drawerMenu.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Tutorial Hidden Drawer', debugShowCheckedModeBanner: false, theme: ThemeData( primarySwatch: Colors.purple, ), home: MainWidget(), ); } }
Selesai. Jika berhasil hasilnya akan seperti dibawah ini

Sedikit memakan waktu namun hasilnya memuaskan karena dengan membuat hidden drawer secara manual seperti ini tentunya kita dapat bebas mengatur tampilkan, animasi dan sebagainya.
Selamat mencoba 🙂