Membuat Hidden Drawer di Flutter

langkah langkah membuat hidden drawer di flutter

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 :

Dengan package hidden_drawer_menu

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

cara menggunakan hidden drawer menu package

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

Membuat Hidden Drawer di Flutter
contoh hidden drawer di flutter

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 🙂

Default image
Omadi Jaya
Fullstack developer, Software Engineer @ Depok, Indonesia

Leave a Reply