Created with <3 with dartpad.dev.
Last active
October 12, 2023 15:24
-
-
Save leonino/ae62bd06b1664540b85c564cc33ea21e to your computer and use it in GitHub Desktop.
Drawer Menu with Reatividade
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file | |
// for details. All rights reserved. Use of this source code is governed by a | |
// BSD-style license that can be found in the LICENSE file. | |
import 'package:flutter/material.dart'; | |
import 'package:provider/provider.dart'; | |
void main() => runApp(MyApp()); | |
class MyApp extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return MultiProvider( | |
providers: [ | |
ChangeNotifierProvider<Configuration>( | |
create: (context) => Configuration(), | |
), | |
], | |
child: Consumer<Configuration>(builder: (_, configuration, __) { | |
return MaterialApp( | |
title: 'Flutter Demo', | |
debugShowCheckedModeBanner: false, | |
themeMode: configuration.getThemeMode, | |
theme: ThemeData( | |
useMaterial3: true, | |
colorSchemeSeed: Colors.green[700], | |
brightness: configuration.getBrightness, | |
), | |
home: const MyHomePage(title: 'Flutter Demo Home Page'), | |
); | |
}), | |
); | |
} | |
} | |
class MyHomePage extends StatefulWidget { | |
final String title; | |
const MyHomePage({ | |
Key? key, | |
required this.title, | |
}) : super(key: key); | |
@override | |
State<MyHomePage> createState() => _MyHomePageState(); | |
} | |
class _MyHomePageState extends State<MyHomePage> { | |
final controller = ScrollController(); | |
var textNameEC = TextEditingController(); | |
var radioValue = 1; | |
var selectedGree = true; | |
var selectedRed = false; | |
var check = List<bool>.from([true, false, false]); | |
List<DropdownMenuItem<String>> cidades = [ | |
"Belem", | |
"Paragominas", | |
"Abaetetuba", | |
"Breves", | |
"Bragre", | |
"Portel", | |
] // | |
.map((e) => DropdownMenuItem( | |
value: e, | |
child: Padding( | |
padding: const EdgeInsets.symmetric(horizontal: 5), | |
child: Text(e)))) | |
.toList(); | |
String cidade = "Paragominas"; | |
onChanged(int? value) { | |
setState(() { | |
radioValue = value ?? 1; | |
}); | |
} | |
@override | |
dispose() { | |
textNameEC.dispose(); | |
super.dispose(); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar( | |
title: Text(widget.title), | |
), | |
body: Container( | |
height: MediaQuery.of(context).size.height, | |
width: MediaQuery.of(context).size.width, | |
padding: EdgeInsets.all(context.toWidthFracao(48)), | |
child: ListView( | |
children: [ | |
const SizedBox(height: 20), | |
Row( | |
children: [ | |
const SizedBox(width: 10), | |
const Expanded( | |
flex: 4, | |
child: Text( | |
"Ativar ou desativar alguma coisa", | |
softWrap: true, | |
overflow: TextOverflow.fade, | |
), | |
), | |
const Spacer(), | |
Switch.adaptive( | |
activeTrackColor: Colors.red, | |
inactiveThumbColor: Colors.red, | |
inactiveTrackColor: Colors.red.shade100, | |
value: selectedRed, | |
onChanged: (value) => setState(() { | |
selectedRed = value; | |
}), | |
), | |
], | |
), | |
const SizedBox(height: 20), | |
TextField( | |
controller: textNameEC, | |
decoration: const InputDecoration( | |
label: Text("Informe qualquer coisa"), | |
border: OutlineInputBorder( | |
borderRadius: BorderRadius.all(Radius.circular(15)), | |
), | |
prefixIcon: Icon(Icons.person), | |
), | |
), | |
const SizedBox(height: 20), | |
Container( | |
clipBehavior: Clip.none, | |
padding: const EdgeInsets.all(10), | |
decoration: BoxDecoration( | |
border: Border.all( | |
color: Theme.of(context).colorScheme.onBackground), | |
borderRadius: BorderRadius.circular(15), | |
), | |
child: Stack( | |
clipBehavior: Clip.none, | |
children: [ | |
Positioned( | |
top: -25, | |
left: 0, | |
child: Container( | |
color: Theme.of(context).colorScheme.background, | |
padding: const EdgeInsets.all(5), | |
child: Text( | |
"Selecione uma opção", | |
softWrap: true, | |
overflow: TextOverflow.fade, | |
style: TextStyle( | |
color: Theme.of(context).colorScheme.primary, | |
fontSize: | |
Theme.of(context).textTheme.bodySmall!.fontSize, | |
), | |
), | |
), | |
), | |
SizedBox( | |
width: double.infinity, | |
child: Wrap( | |
direction: Axis.horizontal, | |
children: [ | |
Row( | |
crossAxisAlignment: CrossAxisAlignment.center, | |
mainAxisSize: MainAxisSize.min, | |
children: [ | |
Radio( | |
groupValue: radioValue, | |
value: 1, | |
onChanged: onChanged, | |
), | |
const Expanded( | |
child: Text( | |
"Opção 01", | |
softWrap: true, | |
overflow: TextOverflow.fade, | |
), | |
), | |
], | |
), | |
const SizedBox(width: 10), | |
Row( | |
crossAxisAlignment: CrossAxisAlignment.center, | |
mainAxisSize: MainAxisSize.min, | |
children: [ | |
Radio( | |
groupValue: radioValue, | |
value: 2, | |
onChanged: onChanged, | |
), | |
const Expanded( | |
child: Text( | |
"Opção 02", | |
softWrap: true, | |
overflow: TextOverflow.fade, | |
), | |
), | |
const SizedBox(width: 10), | |
], | |
), | |
Row( | |
crossAxisAlignment: CrossAxisAlignment.center, | |
mainAxisSize: MainAxisSize.min, | |
children: [ | |
Radio( | |
groupValue: radioValue, | |
value: 3, | |
onChanged: onChanged, | |
), | |
const Expanded( | |
child: Text( | |
"Opção 03", | |
softWrap: true, | |
overflow: TextOverflow.fade, | |
), | |
), | |
const SizedBox(width: 10), | |
], | |
), | |
], | |
), | |
), | |
], | |
), | |
), | |
const SizedBox(height: 20), | |
Container( | |
height: 55, | |
width: double.infinity, | |
padding: const EdgeInsets.all(10), | |
decoration: BoxDecoration( | |
border: Border.all( | |
color: Theme.of(context).colorScheme.onBackground), | |
borderRadius: BorderRadius.circular(15), | |
), | |
child: DropdownButton( | |
items: cidades, | |
value: cidade, | |
isExpanded: true, | |
focusColor: Colors.transparent, | |
underline: const SizedBox(height: 1), | |
iconSize: 30, | |
borderRadius: BorderRadius.circular(15), | |
onChanged: (value) => setState(() { | |
cidade = value!; | |
}), | |
), | |
), | |
const SizedBox(height: 20), | |
Row( | |
children: [ | |
const SizedBox(width: 10), | |
const Expanded( | |
flex: 4, | |
child: Text( | |
"Ativar ou Desativar Algo", | |
softWrap: true, | |
overflow: TextOverflow.fade, | |
), | |
), | |
const Spacer(), | |
Switch.adaptive( | |
value: selectedGree, | |
onChanged: (value) => setState(() { | |
selectedGree = value; | |
}), | |
), | |
], | |
), | |
const SizedBox(height: 20), | |
Container( | |
clipBehavior: Clip.none, | |
padding: const EdgeInsets.all(10), | |
decoration: BoxDecoration( | |
border: Border.all( | |
color: Theme.of(context).colorScheme.onBackground), | |
borderRadius: BorderRadius.circular(15), | |
), | |
child: Stack( | |
clipBehavior: Clip.none, | |
children: [ | |
Positioned( | |
top: -25, | |
left: 0, | |
child: Container( | |
color: Theme.of(context).colorScheme.background, | |
padding: const EdgeInsets.all(5), | |
child: Text( | |
"Marque uma opção", | |
softWrap: true, | |
overflow: TextOverflow.ellipsis, | |
style: TextStyle( | |
color: Theme.of(context).colorScheme.primary, | |
fontSize: | |
Theme.of(context).textTheme.bodySmall!.fontSize, | |
), | |
), | |
), | |
), | |
SizedBox( | |
width: double.infinity, | |
child: Wrap( | |
direction: Axis.horizontal, | |
children: [ | |
Row(children: [ | |
Checkbox( | |
value: check[0], | |
onChanged: (value) => setState(() { | |
check[0] = (value == null) ? false : value; | |
}), | |
), | |
const Text( | |
"Opção 01", | |
softWrap: true, | |
overflow: TextOverflow.fade, | |
), | |
]), | |
Row(children: [ | |
Checkbox( | |
value: check[1], | |
onChanged: (value) => setState(() { | |
check[1] = (value == null) ? false : value; | |
}), | |
), | |
const Expanded( | |
child: Text( | |
"Opção 02", | |
softWrap: true, | |
overflow: TextOverflow.fade, | |
), | |
), | |
]), | |
Row(children: [ | |
Checkbox( | |
value: check[2], | |
onChanged: (value) => setState(() { | |
check[2] = (value == null) ? false : value; | |
}), | |
), | |
const Expanded( | |
child: Text( | |
"Opção 03", | |
softWrap: true, | |
overflow: TextOverflow.fade, | |
), | |
), | |
]), | |
], | |
), | |
), | |
], | |
), | |
), | |
const SizedBox(height: 20), | |
CheckboxListTile( | |
value: check[0], | |
onChanged: (value) => setState(() { | |
check[0] = (value == null) ? false : value; | |
}), | |
title: const Text("Opção 01"), | |
), | |
CheckboxListTile( | |
value: check[1], | |
onChanged: (value) => setState(() { | |
check[1] = (value == null) ? false : value; | |
}), | |
title: const Text("Opção 02"), | |
), | |
CheckboxListTile( | |
value: check[2], | |
onChanged: (value) => setState(() { | |
check[2] = (value == null) ? false : value; | |
}), | |
title: const Text("Opção 03"), | |
), | |
const Divider(), | |
SizedBox( | |
height: 50, | |
width: double.infinity, | |
child: ElevatedButton( | |
onPressed: () {}, | |
child: const Text("Save"), | |
), | |
) | |
], | |
)), | |
drawer: const DrawerWidget(), | |
floatingActionButton: FloatingActionButton( | |
onPressed: () {}, | |
tooltip: 'Increment', | |
child: const Icon(Icons.add), | |
), | |
); | |
} | |
} | |
class DrawerWidget extends StatefulWidget { | |
const DrawerWidget({ | |
Key? key, | |
}) : super(key: key); | |
@override | |
State<DrawerWidget> createState() => _DrawerWidgetState(); | |
} | |
class _DrawerWidgetState extends State<DrawerWidget> { | |
@override | |
Widget build(BuildContext context) { | |
final configuration = context.watch<Configuration>(); | |
final isDarkTheme = Theme.of(context).brightness == Brightness.dark; | |
return Container( | |
color: Theme.of(context).colorScheme.background, | |
height: MediaQuery.of(context).size.height, | |
width: context.toQuaWidth(3), | |
child: Column( | |
mainAxisAlignment: MainAxisAlignment.spaceBetween, | |
children: <Widget>[ | |
Container( | |
color: Theme.of(context).colorScheme.secondary, | |
height: 150, | |
child: Center( | |
child: CircleAvatar( | |
backgroundColor: Theme.of(context).colorScheme.primaryContainer, | |
maxRadius: 35, | |
child: Text( | |
"MR", | |
style: TextStyle( | |
color: Theme.of(context).colorScheme.onPrimaryContainer, | |
), | |
), | |
), | |
), | |
), | |
Expanded( | |
child: ListView( | |
children: <Widget>[ | |
DrawerItem( | |
title: "Theme Mode", | |
icon: isDarkTheme ? Icons.bedtime : Icons.sunny, | |
onTap: () { | |
print("${configuration.value}"); | |
isDarkTheme | |
? configuration.value = ThemeMode.light | |
: configuration.value = ThemeMode.dark; | |
print("${configuration.value}"); | |
setState(() {}); | |
}, | |
), | |
const DrawerItem( | |
title: "Contas", | |
icon: Icons.business_sharp, | |
), | |
const DrawerItem( | |
title: "Cartões", | |
icon: Icons.credit_card, | |
), | |
const DrawerItem( | |
title: "Lancamentos", | |
icon: Icons.money_rounded, | |
), | |
const DrawerItem( | |
title: "Relatorios", | |
icon: Icons.document_scanner_sharp, | |
), | |
const Divider(), | |
const DrawerItem( | |
title: "Sonhos / Metas", | |
icon: Icons.tag_sharp, | |
), | |
], | |
), | |
), | |
const Column( | |
children: [ | |
Divider(), | |
DrawerItem( | |
title: "Sair", | |
icon: Icons.logout_sharp, | |
), | |
], | |
), | |
], | |
), | |
); | |
} | |
} | |
class DrawerItem extends StatelessWidget { | |
final String title; | |
final IconData icon; | |
final VoidCallback? onTap; | |
final Color? color; | |
const DrawerItem({ | |
required this.title, | |
required this.icon, | |
this.onTap, | |
this.color, | |
}); | |
@override | |
Widget build(BuildContext context) { | |
final cor = color ?? Theme.of(context).colorScheme.onBackground; | |
return ListTile( | |
title: Text(title, style: TextStyle(color: cor)), | |
leading: Icon(icon, color: cor), | |
onTap: onTap, | |
); | |
} | |
} | |
/// | |
/// EXTENSIONS | |
/// | |
extension Fracoes on BuildContext { | |
double toDecWidth([int? parte]) => toWidthFracao(10, parte); | |
double toNonWidth([int? parte]) => toWidthFracao(9, parte); | |
double toOitWidth([int? parte]) => toWidthFracao(8, parte); | |
double toSetWidth([int? parte]) => toWidthFracao(7, parte); | |
double toSexWidth([int? parte]) => toWidthFracao(6, parte); | |
double toQuiWidth([int? parte]) => toWidthFracao(5, parte); | |
double toQuaWidth([int? parte]) => toWidthFracao(4, parte); | |
double toTerWidth([int? parte]) => toWidthFracao(3, parte); | |
double toMetWidth([int? parte]) => toWidthFracao(2, parte); | |
double toDecHeight([int? parte]) => toHeightFracao(10, parte); | |
double toNonHeight([int? parte]) => toHeightFracao(9, parte); | |
double toOitHeight([int? parte]) => toHeightFracao(8, parte); | |
double toSetHeight([int? parte]) => toHeightFracao(7, parte); | |
double toSexHeight([int? parte]) => toHeightFracao(6, parte); | |
double toQuiHeight([int? parte]) => toHeightFracao(5, parte); | |
double toQuaHeight([int? parte]) => toHeightFracao(4, parte); | |
double toTerHeight([int? parte]) => toHeightFracao(3, parte); | |
double toMetHeight([int? parte]) => toHeightFracao(2, parte); | |
double toHeightFracao(int partes, [int? parte]) { | |
parte = parte ?? 1; | |
parte = parte > partes || parte == 0 ? partes : parte; | |
return (MediaQuery.of(this).size.height / partes) * parte; | |
} | |
double toWidthFracao(int partes, [int? parte]) { | |
parte = parte ?? 1; | |
parte = parte > partes || parte == 0 ? partes : parte; | |
return (MediaQuery.of(this).size.width / partes) * parte; | |
} | |
} | |
/// | |
/// VALUENOTIFIER | |
/// | |
class Configuration extends ValueNotifier<ThemeMode> { | |
Configuration() : super(ThemeMode.system); | |
ThemeMode get getThemeMode => value; | |
set setTheme(ThemeMode theme) => value = theme; | |
Brightness? get getBrightness => (value == ThemeMode.dark) | |
? Brightness.dark | |
: value == ThemeMode.light | |
? Brightness.light | |
: null; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment