I tried to implement the menu drawer on the main screen to avoid redundancy, it works on the sample screens, however, if the widget structures becomes a little bit complex, the icon button menu cannot access the menu drawer on the main screen.
I can just add endDrawer: CustomDrawer();
on the complex ones but if I do that the menu overlay will only appear as an overlay on the actual screen content, disregarding the bottom navbar.
Here is the main screen code
import 'package:flutter/material.dart';
import 'package:waste_pal/scan.dart';
import 'package:waste_pal/history.dart';
import 'package:waste_pal/profile.dart';
import 'package:waste_pal/home.dart';
import 'package:waste_pal/widgets/bottom-nav.dart';
import 'package:waste_pal/widgets/menu-drawer.dart';
class MainScreen extends StatefulWidget {
@override
_MainScreenState createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
int _selectedIndex = 0;
final List<Widget> _screens = [
HomeScreen(),
ScanScreen(),
HistoryScreen(),
ProfileScreen(),
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
endDrawer: CustomDrawer(),
body: IndexedStack(
index: _selectedIndex,
children: _screens,
),
bottomNavigationBar: CustomNavBar(
selectedIndex: _selectedIndex,
onItemTapped: _onItemTapped,
),
);
}
}
The menu drawer
import 'package:flutter/material.dart';
import 'package:waste_pal/main.dart';
class CustomDrawer extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Drawer(
width: MediaQuery.of(context).size.width * 0.6,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30),
bottomLeft: Radius.circular(30),
),
),
backgroundColor: Color(0xFFBFD9C5),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// Close Button
Padding(
padding: const EdgeInsets.fromLTRB(20, 40, 20, 10),
child: Align(
alignment: Alignment.topLeft,
child: IconButton(
icon: Icon(Icons.close, size: 30, color: Colors.black),
onPressed: () => Navigator.of(context).pop(),
),
),
),
SizedBox(height: 30),
// Menu Items
Expanded(
child: ListView(
padding: EdgeInsets.zero,
children: [
_buildDrawerItem(Icons.home, "Home", context),
_buildDrawerItem(Icons.card_giftcard, "Redeem", context),
_buildDrawerItem(Icons.quiz, "Quizlet", context),
_buildDrawerItem(Icons.library_books, "WasteKnows", context),
_buildDrawerItem(Icons.settings, "Settings", context),
_buildDrawerItem(Icons.help_outline, "Helps & FAQs", context),
],
),
),
// Log Out Button at the Bottom
Padding(
padding: const EdgeInsets.all(20.0),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Color(0xFF2D694F),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
minimumSize: Size(double.infinity, 50),
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => LoginPage()),
);
},
child: Text(
"Log out",
style: TextStyle(color: Colors.white, fontSize: 16),
),
),
),
SizedBox(height: 20),
],
),
);
}
// Helper method for creating menu items
Widget _buildDrawerItem(IconData icon, String title, BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 15.0), // Adjust spacing
child: GestureDetector(
onTap: () => Navigator.pop(context),
child: Row(
mainAxisAlignment: MainAxisAlignment.center, // Center both icon and text
children: [
Icon(icon, color: Color.fromARGB(255, 9, 93, 64)), // Centered Icon
SizedBox(width: 10), // Space between icon and text
Text(
title,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w500),
),
],
),
),
);
}
}
This is the sample screen where the menu works
class HistoryScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("History"),
backgroundColor: Color(0xFF0E5B3B),
leading: IconButton(
icon: Icon(Icons.menu),
onPressed: () {
Scaffold.of(context).openEndDrawer(); // Open drawer
},
),
),
body: Center(child: Text('History Screen', style: TextStyle(fontSize: 24))),
);
}
}
Now this is the complex one
import 'package:flutter/material.dart';
import 'package:camera/camera.dart';
class ScanScreen extends StatefulWidget {
@override
_ScanScreenState createState() => _ScanScreenState();
}
class _ScanScreenState extends State<ScanScreen> {
CameraController? _controller;
List<CameraDescription>? cameras;
bool _isCameraInitialized = false;
@override
void initState() {
super.initState();
_initCamera();
}
Future<void> _initCamera() async {
cameras = await availableCameras();
if (cameras != null && cameras!.isNotEmpty) {
_controller = CameraController(cameras![0], ResolutionPreset.medium);
await _controller!.initialize();
if (!mounted) return;
setState(() {
_isCameraInitialized = true;
});
}
}
@override
void dispose() {
_controller?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(70),
child: AppBar(
elevation: 0,
centerTitle: false,
automaticallyImplyLeading: false,
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Image.asset('assets/logo.png',
height: 70),
Text(
'WASTE PAL',
style: TextStyle(
fontSize: 30,
fontFamily: 'Montserrat',
fontWeight: FontWeight.w900,
color: const Color.fromARGB(255, 35, 62, 46),
),
),
Builder(
builder: (context) => IconButton(
icon: Icon(Icons.menu,
size: 40, color: Color.fromARGB(255, 35, 62, 46)),
onPressed: () {
Scaffold.of(context).openEndDrawer();
},
),
),
],
),
),
),
body: Column(
children: [
Padding(
padding: EdgeInsets.all(10),
child: Container(
padding: EdgeInsets.symmetric(vertical: 20),
width: double.infinity,
decoration: BoxDecoration(
color: Colors.green[800],
borderRadius: BorderRadius.circular(20),
),
child: Center(
child: Text(
'Take a photo of the item',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
fontFamily: 'Montserrat',
color: Colors.white,
),
),
),
),
),
Expanded(
child: _isCameraInitialized
? ClipRRect(
borderRadius: BorderRadius.circular(20),
child: CameraPreview(_controller!),
)
: Center(child: CircularProgressIndicator()),
),
SizedBox(height: 10),
ElevatedButton(
onPressed: () async {
try {
final XFile image = await _controller!.takePicture();
print("Picture taken: ${image.path}");
// You can now use the image path for further processing
} catch (e) {
print("Error capturing image: $e");
}
},
style: ElevatedButton.styleFrom(
shape: CircleBorder(),
padding: EdgeInsets.all(20),
backgroundColor: Colors.green[700],
),
child: Icon(Icons.camera_alt, color: Colors.white, size: 30),
),
SizedBox(height: 20)
],
),
);
}
}
Till I understood your question you are trying to achieve this kind of ui.
This Link can help you to achieve the ui, there are various kinds of GUI available which can help you. I have added code which can also help to achieve the UI, hope it will work.
Plugin :
awesome_drawer_bar: '<latest_release>'
AwesomeDrawerBar(
controller: AwesomeDrawerBarController,
menuScreen: MENU_SCREEN,
mainScreen: MAIN_SCREEN,
borderRadius: 24.0,
showShadow: true,
angle: -12.0,
backgroundColor: Colors.grey[300],
slideWidth: MediaQuery.of(context).size.width*.65,
openCurve: Curves.fastOutSlowIn,
closeCurve: Curves.bounceIn,
)