Skip to content

Instantly share code, notes, and snippets.

@PlugFox
Created December 23, 2023 17:36
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save PlugFox/ed60c155e7792d92b5400ca1652f0c2c to your computer and use it in GitHub Desktop.
Save PlugFox/ed60c155e7792d92b5400ca1652f0c2c to your computer and use it in GitHub Desktop.
Side panel example
/*
* Side panel example
* https://gist.github.com/PlugFox/ed60c155e7792d92b5400ca1652f0c2c
* https://dartpad.dev?id=ed60c155e7792d92b5400ca1652f0c2c
* Matiunin Mikhail <plugfox@gmail.com>, 23 December 2023
*/
import 'dart:async';
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() => runZonedGuarded<void>(
() => runApp(const App()),
(error, stackTrace) => log('Top level exception $error'),
);
class App extends StatelessWidget {
const App({super.key});
@override
Widget build(BuildContext context) => MaterialApp(
title: 'Side menu example',
theme: ThemeData.light(),
home: const HomeScreen(),
builder: (context, child) => SideMenuScope(
menu: const SideMenu(),
child: child ?? const SizedBox.shrink(),
),
);
}
class SideMenuScope extends StatelessWidget {
const SideMenuScope({
required this.menu,
required this.child,
this.width = 256,
super.key, // ignore: unused_element
});
final Widget menu;
final Widget child;
final double width;
Widget _materialContext({required Widget child}) => Material(
child: ScaffoldMessenger(
child: DefaultSelectionStyle(
child: AnimatedTheme(
data: ThemeData.dark(),
duration: const Duration(milliseconds: 350),
curve: Curves.easeInOut,
child: HeroControllerScope.none(
child: Navigator(
pages: <Page<void>>[
MaterialPage<void>(
child: Scaffold(
body: child,
),
),
],
onPopPage: (route, result) => route.didPop(result),
),
),
),
),
),
);
@override
Widget build(BuildContext context) {
final mediaQuery = MediaQuery.of(context);
final width = mediaQuery.size.width / 3 < this.width ? .0 : this.width;
return Stack(
children: <Widget>[
if (width > 0)
Positioned(
key: const ValueKey('menu'),
left: 0,
width: width,
top: 0,
bottom: 0,
child: MediaQuery(
data: mediaQuery.copyWith(
size: Size(width, mediaQuery.size.height),
),
child: _materialContext(
child: menu,
),
),
),
Positioned(
key: const ValueKey('content'),
left: width > 0 ? width : 0,
right: 0,
top: 0,
bottom: 0,
child: MediaQuery(
data: mediaQuery.copyWith(
size: Size(
mediaQuery.size.width - width,
mediaQuery.size.height,
),
),
child: child),
),
],
);
}
}
class SideMenu extends StatefulWidget {
const SideMenu({
super.key, // ignore: unused_element
});
@override
State<SideMenu> createState() => _SideMenuState();
}
class _SideMenuState extends State<SideMenu> {
final TextEditingController _usernameController = TextEditingController(),
_passwordController = TextEditingController();
@override
Widget build(BuildContext context) => Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: AutofillGroup(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SizedBox(
height: 64,
child: TextField(
controller: _usernameController,
autofillHints: const [AutofillHints.username],
decoration: const InputDecoration(
labelText: 'Email',
hintText: 'Enter your email',
border: OutlineInputBorder(),
),
),
),
const SizedBox(height: 8),
SizedBox(
height: 64,
child: TextField(
controller: _passwordController,
autofillHints: const [AutofillHints.password],
obscureText: true,
decoration: const InputDecoration(
labelText: 'Password',
hintText: 'Enter your password',
border: OutlineInputBorder(),
),
),
),
const Divider(
height: 32,
thickness: 1,
),
SizedBox(
height: 64,
child: ElevatedButton(
onPressed: () {
_usernameController.clear();
_passwordController.clear();
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Login'),
),
);
HapticFeedback.lightImpact();
},
child: const Text('Login'),
),
),
],
),
),
),
);
}
class HomeScreen extends StatelessWidget {
const HomeScreen({
super.key, // ignore: unused_element
});
@override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
title: const Text('Home'),
),
body: const SafeArea(
child: Center(
child: Placeholder(),
),
),
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment