Skip to content

Instantly share code, notes, and snippets.

@slightfoot
Last active April 16, 2020 17:48
Show Gist options
  • Save slightfoot/b83dd7446bccbe6f5b768f2d0f4ac8bd to your computer and use it in GitHub Desktop.
Save slightfoot/b83dd7446bccbe6f5b768f2d0f4ac8bd to your computer and use it in GitHub Desktop.
Fab Popup - by Simon Lightfoot - 8th Feburary 2020
// MIT License
//
// Copyright (c) 2020 Simon Lightfoot
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import 'package:flutter/material.dart';
void main() => runApp(ExampleApp());
class ExampleApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
brightness: Brightness.light,
primaryColor: Colors.purple,
accentColor: Colors.tealAccent.shade400,
),
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Scaffold(
drawer: Drawer(),
appBar: AppBar(
title: Text('Inbox'),
actions: <Widget>[
IconButton(
onPressed: () {},
icon: Icon(Icons.search),
),
IconButton(
onPressed: () {},
icon: Icon(Icons.more_vert),
),
],
),
body: SizedBox.expand(
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(vertical: 20.0, horizontal: 16.0),
child: Text('Today', style: theme.textTheme.subtitle1),
),
ListTile(
onTap: () {},
leading: CircleAvatar(backgroundColor: Colors.primaries[0]),
title: Text('Brunch this weekend?'),
subtitle: Text('Ali Connors'),
),
Divider(color: Colors.grey.shade400, indent: 72.0, height: 1.0),
ListTile(
onTap: () {},
leading: CircleAvatar(backgroundColor: Colors.primaries[1]),
title: Text('Brunch this weekend?'),
subtitle: Text('Ali Connors'),
),
Divider(color: Colors.grey.shade400, indent: 72.0, height: 1.0),
ListTile(
onTap: () {},
leading: CircleAvatar(backgroundColor: Colors.primaries[2]),
title: Text('Brunch this weekend?'),
subtitle: Text('Ali Connors'),
),
Divider(color: Colors.grey.shade400, indent: 72.0, height: 1.0),
ListTile(
onTap: () {},
leading: CircleAvatar(backgroundColor: Colors.primaries[3]),
title: Text('Brunch this weekend?'),
subtitle: Text('Ali Connors'),
),
],
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
FabPopupRoute.show(context).then((int index) {
print('Option $index selected');
});
},
child: Icon(Icons.edit),
),
);
}
}
class FabPopupRoute extends PageRoute<int> {
static Future<int> show(BuildContext context) {
return Navigator.of(context).push<int>(FabPopupRoute(
barrierColor: Colors.black38,
barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
));
}
FabPopupRoute({
RouteSettings settings,
@required this.barrierColor,
@required this.barrierLabel,
}) : super(settings: settings);
@override
bool get opaque => false;
@override
bool get maintainState => true;
@override
bool get barrierDismissible => true;
@override
final Color barrierColor;
@override
final String barrierLabel;
@override
Duration get transitionDuration => const Duration(milliseconds: 350);
@override
Widget buildTransitions(
BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
return FadeTransition(
opacity: CurvedAnimation(parent: animation, curve: Curves.easeIn),
child: child,
);
}
void _onItemSelected(BuildContext context, int index) {
Navigator.of(context).pop(index);
}
@override
Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
final theme = Theme.of(context);
return Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: const EdgeInsets.all(16.0) + MediaQuery.of(context).viewInsets,
child: Material(
elevation: 8.0,
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(6.0)),
child: IntrinsicWidth(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
onTap: () => _onItemSelected(context, 0),
leading: CircleAvatar(backgroundColor: Colors.primaries[0]),
title: Text('Sandra Adams'),
),
ListTile(
onTap: () => _onItemSelected(context, 1),
leading: CircleAvatar(backgroundColor: Colors.primaries[1]),
title: Text('Alex Park'),
),
ListTile(
onTap: () => _onItemSelected(context, 2),
leading: CircleAvatar(backgroundColor: Colors.primaries[2]),
title: Text('Charlie Zhao'),
),
Material(
color: theme.accentColor,
child: ListTile(
onTap: () => _onItemSelected(context, 3),
leading: SizedBox(
width: 40.0,
child: Icon(Icons.edit, color: Colors.black),
),
title: Row(
children: <Widget>[
Text('COMPOSE NEW'),
SizedBox(width: 40.0),
],
),
),
),
],
),
),
),
),
);
}
}
@pishguy
Copy link

pishguy commented Apr 16, 2020

@slightfoot you save me a lot of days sir 💯

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment