Reputation: 125
I wish to place a mini button on the left side of the body of the app screen to be used to open a mini drawer in Flutter. To be able to figure it out, I prepared the following image:
As seen, when the user taps on the mini button, a mini drawer-like panel comes in and when the user clicks again on the same button, it closes the panel.
Thank you
Upvotes: 0
Views: 529
Reputation: 79
This code will allow you to use the endDrawer
as your mini drawer, and your main drawer will be there as well.
You can look on the web to customize the end drawer's UI as per your needs.
import 'package:flutter/material.dart';
void main() {
runApp(const MainApp());
}
class MainApp extends StatelessWidget {
const MainApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: Scaffold(
body: TwoDrawers(),
),
);
}
}
class TwoDrawers extends StatelessWidget {
const TwoDrawers({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Mini Drawer"),
actions: const [SizedBox()],
),
drawer: Drawer(
child: Container(
color: Colors.blue,
child: const Center(
child: Text(
"Main Drawer",
style: TextStyle(color: Colors.white, fontSize: 30),
),
),
),
),
endDrawer: SizedBox(
height: 300,
child: Drawer(
elevation: 0,
backgroundColor: Colors.indigo,
child: Row(
children: [
IconButton(
onPressed: () {
Navigator.of(context).pop();
},
icon: const Icon(Icons.chevron_right),
color: Colors.white,
),
Container(
width: 240,
color: Colors.indigo,
child: const Center(
child: Text(
"Mini Drawer",
style: TextStyle(color: Colors.white, fontSize: 30),
),
),
),
],
),
),
),
body: Stack(
children: [
Positioned(
height: 40,
top: 250,
right: -30,
child: SizedBox(
child: Builder(
builder: (context) {
return ElevatedButton(
style: ButtonStyle(
backgroundColor:
const MaterialStatePropertyAll(Colors.indigo),
shape: MaterialStatePropertyAll(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
padding: const MaterialStatePropertyAll(
EdgeInsets.only(right: 30),
),
),
onPressed: () {
Scaffold.of(context).openEndDrawer();
},
child: const Icon(Icons.chevron_left),
);
},
),
),
),
],
),
);
}
}
Some snapshots:
Screen | Main Drawer | Mini Drawer |
---|---|---|
![]() |
![]() |
![]() |
Upvotes: 1
Reputation: 455
You can create your own widget like in the following example.
import 'dart:math';
import 'package:flutter/material.dart';
class MiniDrawer extends StatefulWidget {
final Widget child;
final Widget drawerContent;
final Duration animationDuration;
final Size drawerSize;
final Size drawerButtonSize;
final Color background;
final Color iconColor;
const MiniDrawer({
super.key,
required this.child,
required this.drawerContent,
this.iconColor = Colors.white,
this.background = const Color.fromRGBO(255, 120, 0, 1),
this.drawerSize = const Size(250, 300),
this.drawerButtonSize = const Size(50, 90),
this.animationDuration = const Duration(milliseconds: 200),
});
@override
State<MiniDrawer> createState() => _MiniDrawerState();
}
class _MiniDrawerState extends State<MiniDrawer> {
bool _isOpen = false;
@override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, constraints) {
return Stack(
clipBehavior: Clip.none,
children: [
widget.child,
_buildDrawer(constraints),
],
);
});
}
Widget _buildDrawer(BoxConstraints constraints) {
return AnimatedPositioned(
duration: widget.animationDuration,
top: constraints.maxHeight / 2 - widget.drawerSize.height / 2,
left: _isOpen ? 0 : min(-widget.drawerSize.width, constraints.maxWidth),
child: SizedBox(
height: widget.drawerSize.height,
width: widget.drawerSize.width + widget.drawerButtonSize.width,
child: Stack(
alignment: Alignment.centerRight,
clipBehavior: Clip.none,
children: [
_buildDrawerBtn(),
Row(
children: [
Expanded(
child: SingleChildScrollView(
child: Container(
constraints: BoxConstraints(minHeight: widget.drawerButtonSize.height),
color: widget.background,
child: widget.drawerContent,
),
),
),
SizedBox(width: widget.drawerButtonSize.width),
],
),
],
),
),
);
}
Widget _buildDrawerBtn() {
Radius radius = Radius.circular(widget.drawerButtonSize.height / 2);
return Positioned(
right: 10,
child: GestureDetector(
onTap: () {
setState(() {
_isOpen = !_isOpen;
});
},
child: Container(
decoration: BoxDecoration(
color: widget.background,
borderRadius: BorderRadius.only(
topRight: radius,
bottomRight: radius,
),
),
width: widget.drawerButtonSize.width,
height: widget.drawerButtonSize.height,
child: AnimatedRotation(
duration: widget.animationDuration,
turns: _isOpen ? 0.5 : 0,
child: Icon(
Icons.chevron_right,
size: 32,
color: widget.iconColor,
),
),
),
),
);
}
}
And then you can use that widget in your code like this.
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('app bar')),
body: MiniDrawer(
drawerContent: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: List.generate(
10,
(index) => ListTile(
title: Text('Item $index'),
),
),
),
),
child: const Column(
children: [
Text('Page content'),
],
),
),
);
}
Upvotes: 1