| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308 |
- // Copyright 2021 The Flutter team. 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:flutter/services.dart';
- const rowDivider = SizedBox(width: 20);
- const colDivider = SizedBox(height: 10);
- const tinySpacing = 3.0;
- const smallSpacing = 10.0;
- const double cardWidth = 115;
- const double widthConstraint = 450;
- class FirstComponentList extends StatelessWidget {
- const FirstComponentList({
- super.key,
- required this.showNavBottomBar,
- required this.scaffoldKey,
- required this.showSecondList,
- });
- final bool showNavBottomBar;
- final GlobalKey<ScaffoldState> scaffoldKey;
- final bool showSecondList;
- @override
- Widget build(BuildContext context) {
- // Fully traverse this list before moving on.
- return FocusTraversalGroup(
- child: ListView(
- padding: showSecondList
- ? const EdgeInsetsDirectional.only(end: smallSpacing)
- : EdgeInsets.zero,
- children: [
- const Actions(),
- colDivider,
- const Communication(),
- colDivider,
- const Containment(),
- if (!showSecondList) ...[
- colDivider,
- Navigation(scaffoldKey: scaffoldKey),
- colDivider,
- const Selection(),
- colDivider,
- const TextInputs()
- ],
- ],
- ),
- );
- }
- }
- class SecondComponentList extends StatelessWidget {
- const SecondComponentList({
- super.key,
- required this.scaffoldKey,
- });
- final GlobalKey<ScaffoldState> scaffoldKey;
- @override
- Widget build(BuildContext context) {
- // Fully traverse this list before moving on.
- return FocusTraversalGroup(
- child: ListView(
- padding: const EdgeInsetsDirectional.only(end: smallSpacing),
- children: <Widget>[
- Navigation(scaffoldKey: scaffoldKey),
- colDivider,
- const Selection(),
- colDivider,
- const TextInputs(),
- ],
- ),
- );
- }
- }
- class Actions extends StatelessWidget {
- const Actions({super.key});
- @override
- Widget build(BuildContext context) {
- return const ComponentGroupDecoration(label: 'Actions', children: <Widget>[
- Buttons(),
- FloatingActionButtons(),
- IconToggleButtons(),
- SegmentedButtons(),
- ]);
- }
- }
- class Communication extends StatelessWidget {
- const Communication({super.key});
- @override
- Widget build(BuildContext context) {
- return const ComponentGroupDecoration(label: 'Communication', children: [
- NavigationBars(
- selectedIndex: 1,
- isExampleBar: true,
- isBadgeExample: true,
- ),
- ProgressIndicators(),
- SnackBarSection(),
- ]);
- }
- }
- class Containment extends StatelessWidget {
- const Containment({super.key});
- @override
- Widget build(BuildContext context) {
- return const ComponentGroupDecoration(label: 'Containment', children: [
- BottomSheetSection(),
- Cards(),
- Dialogs(),
- Dividers(),
- // TODO: Add Lists, https://github.com/flutter/flutter/issues/114006
- // TODO: Add Side sheets, https://github.com/flutter/flutter/issues/119328
- ]);
- }
- }
- class Navigation extends StatelessWidget {
- const Navigation({super.key, required this.scaffoldKey});
- final GlobalKey<ScaffoldState> scaffoldKey;
- @override
- Widget build(BuildContext context) {
- return ComponentGroupDecoration(label: 'Navigation', children: [
- const BottomAppBars(),
- const NavigationBars(
- selectedIndex: 0,
- isExampleBar: true,
- ),
- NavigationDrawers(scaffoldKey: scaffoldKey),
- const NavigationRails(),
- // TODO: Add Search https://github.com/flutter/flutter/issues/117483
- const Tabs(),
- const TopAppBars(),
- ]);
- }
- }
- class Selection extends StatelessWidget {
- const Selection({super.key});
- @override
- Widget build(BuildContext context) {
- return const ComponentGroupDecoration(label: 'Selection', children: [
- Checkboxes(),
- Chips(),
- // TODO: Add Date pickers https://github.com/flutter/flutter/issues/101481
- Menus(),
- Radios(),
- Sliders(),
- Switches(),
- // TODO: Add Time pickers https://github.com/flutter/flutter/issues/101480
- ]);
- }
- }
- class TextInputs extends StatelessWidget {
- const TextInputs({super.key});
- @override
- Widget build(BuildContext context) {
- return const ComponentGroupDecoration(
- label: 'Text inputs',
- children: [TextFields()],
- );
- }
- }
- class Buttons extends StatefulWidget {
- const Buttons({super.key});
- @override
- State<Buttons> createState() => _ButtonsState();
- }
- class _ButtonsState extends State<Buttons> {
- @override
- Widget build(BuildContext context) {
- return ComponentDecoration(
- label: 'Common buttons',
- tooltipMessage:
- 'Use ElevatedButton, FilledButton, FilledButton.tonal, OutlinedButton, or TextButton',
- child: SingleChildScrollView(
- scrollDirection: Axis.horizontal,
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceAround,
- children: const <Widget>[
- ButtonsWithoutIcon(isDisabled: false),
- ButtonsWithIcon(),
- ButtonsWithoutIcon(isDisabled: true),
- ],
- ),
- ),
- );
- }
- }
- class ButtonsWithoutIcon extends StatelessWidget {
- final bool isDisabled;
- const ButtonsWithoutIcon({super.key, required this.isDisabled});
- @override
- Widget build(BuildContext context) {
- return Padding(
- padding: const EdgeInsets.symmetric(horizontal: 5.0),
- child: IntrinsicWidth(
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.stretch,
- children: <Widget>[
- ElevatedButton(
- onPressed: isDisabled ? null : () {},
- child: const Text('Elevated'),
- ),
- colDivider,
- FilledButton(
- onPressed: isDisabled ? null : () {},
- child: const Text('Filled'),
- ),
- colDivider,
- FilledButton.tonal(
- onPressed: isDisabled ? null : () {},
- child: const Text('Filled tonal'),
- ),
- colDivider,
- OutlinedButton(
- onPressed: isDisabled ? null : () {},
- child: const Text('Outlined'),
- ),
- colDivider,
- TextButton(
- onPressed: isDisabled ? null : () {},
- child: const Text('Text'),
- ),
- ],
- ),
- ),
- );
- }
- }
- class ButtonsWithIcon extends StatelessWidget {
- const ButtonsWithIcon({super.key});
- @override
- Widget build(BuildContext context) {
- return Padding(
- padding: const EdgeInsets.symmetric(horizontal: 10.0),
- child: IntrinsicWidth(
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.stretch,
- children: <Widget>[
- ElevatedButton.icon(
- onPressed: () {},
- icon: const Icon(Icons.add),
- label: const Text('Icon'),
- ),
- colDivider,
- FilledButton.icon(
- onPressed: () {},
- label: const Text('Icon'),
- icon: const Icon(Icons.add),
- ),
- colDivider,
- FilledButton.tonalIcon(
- onPressed: () {},
- label: const Text('Icon'),
- icon: const Icon(Icons.add),
- ),
- colDivider,
- OutlinedButton.icon(
- onPressed: () {},
- icon: const Icon(Icons.add),
- label: const Text('Icon'),
- ),
- colDivider,
- TextButton.icon(
- onPressed: () {},
- icon: const Icon(Icons.add),
- label: const Text('Icon'),
- )
- ],
- ),
- ),
- );
- }
- }
- class FloatingActionButtons extends StatelessWidget {
- const FloatingActionButtons({super.key});
- @override
- Widget build(BuildContext context) {
- return ComponentDecoration(
- label: 'Floating action buttons',
- tooltipMessage:
- 'Use FloatingActionButton or FloatingActionButton.extended',
- child: Wrap(
- crossAxisAlignment: WrapCrossAlignment.center,
- runSpacing: smallSpacing,
- spacing: smallSpacing,
- children: [
- FloatingActionButton.small(
- onPressed: () {},
- tooltip: 'Small',
- child: const Icon(Icons.add),
- ),
- FloatingActionButton.extended(
- onPressed: () {},
- tooltip: 'Extended',
- icon: const Icon(Icons.add),
- label: const Text('Create'),
- ),
- FloatingActionButton(
- onPressed: () {},
- tooltip: 'Standard',
- child: const Icon(Icons.add),
- ),
- FloatingActionButton.large(
- onPressed: () {},
- tooltip: 'Large',
- child: const Icon(Icons.add),
- ),
- ],
- ),
- );
- }
- }
- class Cards extends StatelessWidget {
- const Cards({super.key});
- @override
- Widget build(BuildContext context) {
- return ComponentDecoration(
- label: 'Cards',
- tooltipMessage: 'Use Card',
- child: Wrap(
- alignment: WrapAlignment.spaceEvenly,
- children: [
- SizedBox(
- width: cardWidth,
- child: Card(
- child: Container(
- padding: const EdgeInsets.fromLTRB(10, 5, 5, 10),
- child: Column(
- children: [
- Align(
- alignment: Alignment.topRight,
- child: IconButton(
- icon: const Icon(Icons.more_vert),
- onPressed: () {},
- ),
- ),
- const SizedBox(height: 20),
- const Align(
- alignment: Alignment.bottomLeft,
- child: Text('Elevated'),
- )
- ],
- ),
- ),
- ),
- ),
- SizedBox(
- width: cardWidth,
- child: Card(
- color: Theme.of(context).colorScheme.surfaceVariant,
- elevation: 0,
- child: Container(
- padding: const EdgeInsets.fromLTRB(10, 5, 5, 10),
- child: Column(
- children: [
- Align(
- alignment: Alignment.topRight,
- child: IconButton(
- icon: const Icon(Icons.more_vert),
- onPressed: () {},
- ),
- ),
- const SizedBox(height: 20),
- const Align(
- alignment: Alignment.bottomLeft,
- child: Text('Filled'),
- )
- ],
- ),
- ),
- ),
- ),
- SizedBox(
- width: cardWidth,
- child: Card(
- elevation: 0,
- shape: RoundedRectangleBorder(
- side: BorderSide(
- color: Theme.of(context).colorScheme.outline,
- ),
- borderRadius: const BorderRadius.all(Radius.circular(12)),
- ),
- child: Container(
- padding: const EdgeInsets.fromLTRB(10, 5, 5, 10),
- child: Column(
- children: [
- Align(
- alignment: Alignment.topRight,
- child: IconButton(
- icon: const Icon(Icons.more_vert),
- onPressed: () {},
- ),
- ),
- const SizedBox(height: 20),
- const Align(
- alignment: Alignment.bottomLeft,
- child: Text('Outlined'),
- )
- ],
- ),
- ),
- ),
- ),
- ],
- ),
- );
- }
- }
- class _ClearButton extends StatelessWidget {
- const _ClearButton({required this.controller});
- final TextEditingController controller;
- @override
- Widget build(BuildContext context) => IconButton(
- icon: const Icon(Icons.clear),
- onPressed: () => controller.clear(),
- );
- }
- class TextFields extends StatefulWidget {
- const TextFields({super.key});
- @override
- State<TextFields> createState() => _TextFieldsState();
- }
- class _TextFieldsState extends State<TextFields> {
- final TextEditingController _controllerFilled = TextEditingController();
- final TextEditingController _controllerOutlined = TextEditingController();
- @override
- Widget build(BuildContext context) {
- return ComponentDecoration(
- label: 'Text fields',
- tooltipMessage: 'Use TextField with different InputDecoration',
- child: Column(
- mainAxisAlignment: MainAxisAlignment.start,
- children: [
- Padding(
- padding: const EdgeInsets.all(smallSpacing),
- child: TextField(
- controller: _controllerFilled,
- decoration: InputDecoration(
- prefixIcon: const Icon(Icons.search),
- suffixIcon: _ClearButton(controller: _controllerFilled),
- labelText: 'Filled',
- hintText: 'hint text',
- helperText: 'supporting text',
- filled: true,
- ),
- ),
- ),
- Padding(
- padding: const EdgeInsets.all(smallSpacing),
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- Flexible(
- child: SizedBox(
- width: 200,
- child: TextField(
- maxLength: 10,
- maxLengthEnforcement: MaxLengthEnforcement.none,
- controller: _controllerFilled,
- decoration: InputDecoration(
- prefixIcon: const Icon(Icons.search),
- suffixIcon: _ClearButton(controller: _controllerFilled),
- labelText: 'Filled',
- hintText: 'hint text',
- helperText: 'supporting text',
- filled: true,
- errorText: 'error text',
- ),
- ),
- ),
- ),
- const SizedBox(width: smallSpacing),
- Flexible(
- child: SizedBox(
- width: 200,
- child: TextField(
- controller: _controllerFilled,
- enabled: false,
- decoration: InputDecoration(
- prefixIcon: const Icon(Icons.search),
- suffixIcon: _ClearButton(controller: _controllerFilled),
- labelText: 'Disabled',
- hintText: 'hint text',
- helperText: 'supporting text',
- filled: true,
- ),
- ),
- ),
- ),
- ],
- ),
- ),
- Padding(
- padding: const EdgeInsets.all(smallSpacing),
- child: TextField(
- controller: _controllerOutlined,
- decoration: InputDecoration(
- prefixIcon: const Icon(Icons.search),
- suffixIcon: _ClearButton(controller: _controllerOutlined),
- labelText: 'Outlined',
- hintText: 'hint text',
- helperText: 'supporting text',
- border: const OutlineInputBorder(),
- ),
- ),
- ),
- Padding(
- padding: const EdgeInsets.all(smallSpacing),
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- Flexible(
- child: SizedBox(
- width: 200,
- child: TextField(
- controller: _controllerOutlined,
- decoration: InputDecoration(
- prefixIcon: const Icon(Icons.search),
- suffixIcon:
- _ClearButton(controller: _controllerOutlined),
- labelText: 'Outlined',
- hintText: 'hint text',
- helperText: 'supporting text',
- errorText: 'error text',
- border: const OutlineInputBorder(),
- filled: true,
- ),
- ),
- ),
- ),
- const SizedBox(width: smallSpacing),
- Flexible(
- child: SizedBox(
- width: 200,
- child: TextField(
- controller: _controllerOutlined,
- enabled: false,
- decoration: InputDecoration(
- prefixIcon: const Icon(Icons.search),
- suffixIcon:
- _ClearButton(controller: _controllerOutlined),
- labelText: 'Disabled',
- hintText: 'hint text',
- helperText: 'supporting text',
- border: const OutlineInputBorder(),
- filled: true,
- ),
- ),
- ),
- ),
- ])),
- ],
- ),
- );
- }
- }
- class Dialogs extends StatefulWidget {
- const Dialogs({super.key});
- @override
- State<Dialogs> createState() => _DialogsState();
- }
- class _DialogsState extends State<Dialogs> {
- void openDialog(BuildContext context) {
- showDialog<void>(
- context: context,
- builder: (context) => AlertDialog(
- title: const Text('What is a dialog?'),
- content: const Text(
- 'A dialog is a type of modal window that appears in front of app content to provide critical information, or prompt for a decision to be made.'),
- actions: <Widget>[
- TextButton(
- child: const Text('Okay'),
- onPressed: () => Navigator.of(context).pop(),
- ),
- FilledButton(
- child: const Text('Dismiss'),
- onPressed: () => Navigator.of(context).pop(),
- ),
- ],
- ),
- );
- }
- void openFullscreenDialog(BuildContext context) {
- showDialog<void>(
- context: context,
- builder: (context) => Dialog.fullscreen(
- child: Padding(
- padding: const EdgeInsets.all(20.0),
- child: Scaffold(
- appBar: AppBar(
- title: const Text('Full-screen dialog'),
- centerTitle: false,
- leading: IconButton(
- icon: const Icon(Icons.close),
- onPressed: () => Navigator.of(context).pop(),
- ),
- actions: [
- TextButton(
- child: const Text('Close'),
- onPressed: () => Navigator.of(context).pop(),
- ),
- ],
- ),
- ),
- ),
- ),
- );
- }
- @override
- Widget build(BuildContext context) {
- return ComponentDecoration(
- label: 'Dialog',
- tooltipMessage:
- 'Use showDialog with Dialog.fullscreen, AlertDialog, or SimpleDialog',
- child: Wrap(
- alignment: WrapAlignment.spaceBetween,
- children: [
- TextButton(
- child: const Text(
- 'Show dialog',
- style: TextStyle(fontWeight: FontWeight.bold),
- ),
- onPressed: () => openDialog(context),
- ),
- TextButton(
- child: const Text(
- 'Show full-screen dialog',
- style: TextStyle(fontWeight: FontWeight.bold),
- ),
- onPressed: () => openFullscreenDialog(context),
- ),
- ],
- ),
- );
- }
- }
- class Dividers extends StatelessWidget {
- const Dividers({super.key});
- @override
- Widget build(BuildContext context) {
- return ComponentDecoration(
- label: 'Dividers',
- tooltipMessage: 'Use Divider or VerticalDivider',
- child: Column(
- children: const <Widget>[
- Divider(key: Key('divider')),
- ],
- ),
- );
- }
- }
- class Switches extends StatelessWidget {
- const Switches({super.key});
- @override
- Widget build(BuildContext context) {
- return ComponentDecoration(
- label: 'Switches',
- tooltipMessage: 'Use SwitchListTile or Switch',
- child: Column(
- children: const <Widget>[
- SwitchRow(isEnabled: true),
- SwitchRow(isEnabled: false),
- ],
- ),
- );
- }
- }
- class SwitchRow extends StatefulWidget {
- const SwitchRow({super.key, required this.isEnabled});
- final bool isEnabled;
- @override
- State<SwitchRow> createState() => _SwitchRowState();
- }
- class _SwitchRowState extends State<SwitchRow> {
- bool value0 = false;
- bool value1 = true;
- final MaterialStateProperty<Icon?> thumbIcon =
- MaterialStateProperty.resolveWith<Icon?>((states) {
- if (states.contains(MaterialState.selected)) {
- return const Icon(Icons.check);
- }
- return const Icon(Icons.close);
- });
- @override
- Widget build(BuildContext context) {
- return Row(
- mainAxisAlignment: MainAxisAlignment.spaceEvenly,
- children: <Widget>[
- // TODO: use SwitchListTile when thumbIcon is available https://github.com/flutter/flutter/issues/118616
- Switch(
- value: value0,
- onChanged: widget.isEnabled
- ? (value) {
- setState(() {
- value0 = value;
- });
- }
- : null,
- ),
- Switch(
- thumbIcon: thumbIcon,
- value: value1,
- onChanged: widget.isEnabled
- ? (value) {
- setState(() {
- value1 = value;
- });
- }
- : null,
- ),
- ],
- );
- }
- }
- class Checkboxes extends StatefulWidget {
- const Checkboxes({super.key});
- @override
- State<Checkboxes> createState() => _CheckboxesState();
- }
- class _CheckboxesState extends State<Checkboxes> {
- bool? isChecked0 = true;
- bool? isChecked1;
- bool? isChecked2 = false;
- @override
- Widget build(BuildContext context) {
- return ComponentDecoration(
- label: 'Checkboxes',
- tooltipMessage: 'Use CheckboxListTile or Checkbox',
- child: Column(
- children: <Widget>[
- CheckboxListTile(
- tristate: true,
- value: isChecked0,
- title: const Text('Option 1'),
- onChanged: (value) {
- setState(() {
- isChecked0 = value;
- });
- },
- ),
- CheckboxListTile(
- tristate: true,
- value: isChecked1,
- title: const Text('Option 2'),
- onChanged: (value) {
- setState(() {
- isChecked1 = value;
- });
- },
- ),
- CheckboxListTile(
- tristate: true,
- value: isChecked2,
- title: const Text('Option 3'),
- // TODO: showcase error state https://github.com/flutter/flutter/issues/118616
- onChanged: (value) {
- setState(() {
- isChecked2 = value;
- });
- },
- ),
- const CheckboxListTile(
- tristate: true,
- title: Text('Option 4'),
- value: true,
- onChanged: null,
- ),
- ],
- ),
- );
- }
- }
- enum Value { first, second }
- class Radios extends StatefulWidget {
- const Radios({super.key});
- @override
- State<Radios> createState() => _RadiosState();
- }
- enum Options { option1, option2, option3 }
- class _RadiosState extends State<Radios> {
- Options? _selectedOption = Options.option1;
- @override
- Widget build(BuildContext context) {
- return ComponentDecoration(
- label: 'Radio buttons',
- tooltipMessage: 'Use RadioListTile<T> or Radio<T>',
- child: Column(
- children: <Widget>[
- RadioListTile<Options>(
- title: const Text('Option 1'),
- value: Options.option1,
- groupValue: _selectedOption,
- onChanged: (value) {
- setState(() {
- _selectedOption = value;
- });
- },
- ),
- RadioListTile<Options>(
- title: const Text('Option 2'),
- value: Options.option2,
- groupValue: _selectedOption,
- onChanged: (value) {
- setState(() {
- _selectedOption = value;
- });
- },
- ),
- RadioListTile<Options>(
- title: const Text('Option 3'),
- value: Options.option3,
- groupValue: _selectedOption,
- onChanged: null,
- ),
- ],
- ),
- );
- }
- }
- class ProgressIndicators extends StatefulWidget {
- const ProgressIndicators({super.key});
- @override
- State<ProgressIndicators> createState() => _ProgressIndicatorsState();
- }
- class _ProgressIndicatorsState extends State<ProgressIndicators> {
- bool playProgressIndicator = false;
- @override
- Widget build(BuildContext context) {
- final double? progressValue = playProgressIndicator ? null : 0.7;
- return ComponentDecoration(
- label: 'Progress indicators',
- tooltipMessage:
- 'Use CircularProgressIndicator or LinearProgressIndicator',
- child: Column(
- children: <Widget>[
- Row(
- children: [
- IconButton(
- isSelected: playProgressIndicator,
- selectedIcon: const Icon(Icons.pause),
- icon: const Icon(Icons.play_arrow),
- onPressed: () {
- setState(() {
- playProgressIndicator = !playProgressIndicator;
- });
- },
- ),
- Expanded(
- child: Row(
- children: <Widget>[
- rowDivider,
- CircularProgressIndicator(
- value: progressValue,
- ),
- rowDivider,
- Expanded(
- child: LinearProgressIndicator(
- value: progressValue,
- ),
- ),
- rowDivider,
- ],
- ),
- ),
- ],
- ),
- ],
- ),
- );
- }
- }
- const List<NavigationDestination> appBarDestinations = [
- NavigationDestination(
- tooltip: '',
- icon: Icon(Icons.widgets_outlined),
- label: 'Components',
- selectedIcon: Icon(Icons.widgets),
- ),
- NavigationDestination(
- tooltip: '',
- icon: Icon(Icons.format_paint_outlined),
- label: 'Color',
- selectedIcon: Icon(Icons.format_paint),
- ),
- NavigationDestination(
- tooltip: '',
- icon: Icon(Icons.text_snippet_outlined),
- label: 'Typography',
- selectedIcon: Icon(Icons.text_snippet),
- ),
- NavigationDestination(
- tooltip: '',
- icon: Icon(Icons.invert_colors_on_outlined),
- label: 'Elevation',
- selectedIcon: Icon(Icons.opacity),
- )
- ];
- const List<Widget> exampleBarDestinations = [
- NavigationDestination(
- tooltip: '',
- icon: Icon(Icons.explore_outlined),
- label: 'Explore',
- selectedIcon: Icon(Icons.explore),
- ),
- NavigationDestination(
- tooltip: '',
- icon: Icon(Icons.pets_outlined),
- label: 'Pets',
- selectedIcon: Icon(Icons.pets),
- ),
- NavigationDestination(
- tooltip: '',
- icon: Icon(Icons.account_box_outlined),
- label: 'Account',
- selectedIcon: Icon(Icons.account_box),
- )
- ];
- List<Widget> barWithBadgeDestinations = [
- NavigationDestination(
- tooltip: '',
- icon: Badge.count(count: 1000, child: const Icon(Icons.mail_outlined)),
- label: 'Mail',
- selectedIcon: Badge.count(count: 1000, child: const Icon(Icons.mail)),
- ),
- const NavigationDestination(
- tooltip: '',
- icon: Badge(label: Text('10'), child: Icon(Icons.chat_bubble_outline)),
- label: 'Chat',
- selectedIcon: Badge(label: Text('10'), child: Icon(Icons.chat_bubble)),
- ),
- const NavigationDestination(
- tooltip: '',
- icon: Badge(child: Icon(Icons.group_outlined)),
- label: 'Rooms',
- selectedIcon: Badge(child: Icon(Icons.group_rounded)),
- ),
- NavigationDestination(
- tooltip: '',
- icon: Badge.count(count: 3, child: const Icon(Icons.videocam_outlined)),
- label: 'Meet',
- selectedIcon: Badge.count(count: 3, child: const Icon(Icons.videocam)),
- )
- ];
- class NavigationBars extends StatefulWidget {
- const NavigationBars({
- super.key,
- this.onSelectItem,
- required this.selectedIndex,
- required this.isExampleBar,
- this.isBadgeExample = false,
- });
- final void Function(int)? onSelectItem;
- final int selectedIndex;
- final bool isExampleBar;
- final bool isBadgeExample;
- @override
- State<NavigationBars> createState() => _NavigationBarsState();
- }
- class _NavigationBarsState extends State<NavigationBars> {
- late int selectedIndex;
- @override
- void initState() {
- super.initState();
- selectedIndex = widget.selectedIndex;
- }
- @override
- void didUpdateWidget(covariant NavigationBars oldWidget) {
- super.didUpdateWidget(oldWidget);
- if (widget.selectedIndex != oldWidget.selectedIndex) {
- selectedIndex = widget.selectedIndex;
- }
- }
- @override
- Widget build(BuildContext context) {
- // App NavigationBar should get first focus.
- Widget navigationBar = Focus(
- autofocus: !(widget.isExampleBar || widget.isBadgeExample),
- child: NavigationBar(
- selectedIndex: selectedIndex,
- onDestinationSelected: (index) {
- setState(() {
- selectedIndex = index;
- });
- if (!widget.isExampleBar) widget.onSelectItem!(index);
- },
- destinations: widget.isExampleBar && widget.isBadgeExample
- ? barWithBadgeDestinations
- : widget.isExampleBar
- ? exampleBarDestinations
- : appBarDestinations,
- ),
- );
- if (widget.isExampleBar && widget.isBadgeExample) {
- navigationBar = ComponentDecoration(
- label: 'Badges',
- tooltipMessage: 'Use Badge or Badge.count',
- child: navigationBar);
- } else if (widget.isExampleBar) {
- navigationBar = ComponentDecoration(
- label: 'Navigation bar',
- tooltipMessage: 'Use NavigationBar',
- child: navigationBar);
- }
- return navigationBar;
- }
- }
- class IconToggleButtons extends StatefulWidget {
- const IconToggleButtons({super.key});
- @override
- State<IconToggleButtons> createState() => _IconToggleButtonsState();
- }
- class _IconToggleButtonsState extends State<IconToggleButtons> {
- @override
- Widget build(BuildContext context) {
- return ComponentDecoration(
- label: 'Icon buttons',
- tooltipMessage: 'Use IconButton',
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceAround,
- children: <Widget>[
- Column(
- // Standard IconButton
- children: const <Widget>[
- IconToggleButton(
- isEnabled: true,
- tooltip: 'Standard',
- ),
- colDivider,
- IconToggleButton(
- isEnabled: false,
- tooltip: 'Standard (disabled)',
- ),
- ],
- ),
- Column(
- children: const <Widget>[
- // Filled IconButton
- IconToggleButton(
- isEnabled: true,
- tooltip: 'Filled',
- getDefaultStyle: enabledFilledButtonStyle,
- ),
- colDivider,
- IconToggleButton(
- isEnabled: false,
- tooltip: 'Filled (disabled)',
- getDefaultStyle: disabledFilledButtonStyle,
- ),
- ],
- ),
- Column(
- children: const <Widget>[
- // Filled Tonal IconButton
- IconToggleButton(
- isEnabled: true,
- tooltip: 'Filled tonal',
- getDefaultStyle: enabledFilledTonalButtonStyle,
- ),
- colDivider,
- IconToggleButton(
- isEnabled: false,
- tooltip: 'Filled tonal (disabled)',
- getDefaultStyle: disabledFilledTonalButtonStyle,
- ),
- ],
- ),
- Column(
- children: const <Widget>[
- // Outlined IconButton
- IconToggleButton(
- isEnabled: true,
- tooltip: 'Outlined',
- getDefaultStyle: enabledOutlinedButtonStyle,
- ),
- colDivider,
- IconToggleButton(
- isEnabled: false,
- tooltip: 'Outlined (disabled)',
- getDefaultStyle: disabledOutlinedButtonStyle,
- ),
- ],
- ),
- ],
- ),
- );
- }
- }
- class IconToggleButton extends StatefulWidget {
- const IconToggleButton({
- required this.isEnabled,
- required this.tooltip,
- this.getDefaultStyle,
- super.key,
- });
- final bool isEnabled;
- final String tooltip;
- final ButtonStyle? Function(bool, ColorScheme)? getDefaultStyle;
- @override
- State<IconToggleButton> createState() => _IconToggleButtonState();
- }
- class _IconToggleButtonState extends State<IconToggleButton> {
- bool selected = false;
- @override
- Widget build(BuildContext context) {
- final ColorScheme colors = Theme.of(context).colorScheme;
- final VoidCallback? onPressed = widget.isEnabled
- ? () {
- setState(() {
- selected = !selected;
- });
- }
- : null;
- ButtonStyle? style = widget.getDefaultStyle?.call(selected, colors);
- return IconButton(
- visualDensity: VisualDensity.standard,
- isSelected: selected,
- tooltip: widget.tooltip,
- icon: const Icon(Icons.settings_outlined),
- selectedIcon: const Icon(Icons.settings),
- onPressed: onPressed,
- style: style,
- );
- }
- }
- ButtonStyle enabledFilledButtonStyle(bool selected, ColorScheme colors) {
- return IconButton.styleFrom(
- foregroundColor: selected ? colors.onPrimary : colors.primary,
- backgroundColor: selected ? colors.primary : colors.surfaceVariant,
- disabledForegroundColor: colors.onSurface.withOpacity(0.38),
- disabledBackgroundColor: colors.onSurface.withOpacity(0.12),
- hoverColor: selected
- ? colors.onPrimary.withOpacity(0.08)
- : colors.primary.withOpacity(0.08),
- focusColor: selected
- ? colors.onPrimary.withOpacity(0.12)
- : colors.primary.withOpacity(0.12),
- highlightColor: selected
- ? colors.onPrimary.withOpacity(0.12)
- : colors.primary.withOpacity(0.12),
- );
- }
- ButtonStyle disabledFilledButtonStyle(bool selected, ColorScheme colors) {
- return IconButton.styleFrom(
- disabledForegroundColor: colors.onSurface.withOpacity(0.38),
- disabledBackgroundColor: colors.onSurface.withOpacity(0.12),
- );
- }
- ButtonStyle enabledFilledTonalButtonStyle(bool selected, ColorScheme colors) {
- return IconButton.styleFrom(
- foregroundColor:
- selected ? colors.onSecondaryContainer : colors.onSurfaceVariant,
- backgroundColor:
- selected ? colors.secondaryContainer : colors.surfaceVariant,
- hoverColor: selected
- ? colors.onSecondaryContainer.withOpacity(0.08)
- : colors.onSurfaceVariant.withOpacity(0.08),
- focusColor: selected
- ? colors.onSecondaryContainer.withOpacity(0.12)
- : colors.onSurfaceVariant.withOpacity(0.12),
- highlightColor: selected
- ? colors.onSecondaryContainer.withOpacity(0.12)
- : colors.onSurfaceVariant.withOpacity(0.12),
- );
- }
- ButtonStyle disabledFilledTonalButtonStyle(bool selected, ColorScheme colors) {
- return IconButton.styleFrom(
- disabledForegroundColor: colors.onSurface.withOpacity(0.38),
- disabledBackgroundColor: colors.onSurface.withOpacity(0.12),
- );
- }
- ButtonStyle enabledOutlinedButtonStyle(bool selected, ColorScheme colors) {
- return IconButton.styleFrom(
- backgroundColor: selected ? colors.inverseSurface : null,
- hoverColor: selected
- ? colors.onInverseSurface.withOpacity(0.08)
- : colors.onSurfaceVariant.withOpacity(0.08),
- focusColor: selected
- ? colors.onInverseSurface.withOpacity(0.12)
- : colors.onSurfaceVariant.withOpacity(0.12),
- highlightColor: selected
- ? colors.onInverseSurface.withOpacity(0.12)
- : colors.onSurface.withOpacity(0.12),
- side: BorderSide(color: colors.outline),
- ).copyWith(
- foregroundColor: MaterialStateProperty.resolveWith((states) {
- if (states.contains(MaterialState.selected)) {
- return colors.onInverseSurface;
- }
- if (states.contains(MaterialState.pressed)) {
- return colors.onSurface;
- }
- return null;
- }),
- );
- }
- ButtonStyle disabledOutlinedButtonStyle(bool selected, ColorScheme colors) {
- return IconButton.styleFrom(
- disabledForegroundColor: colors.onSurface.withOpacity(0.38),
- disabledBackgroundColor:
- selected ? colors.onSurface.withOpacity(0.12) : null,
- side: selected ? null : BorderSide(color: colors.outline.withOpacity(0.12)),
- );
- }
- class Chips extends StatefulWidget {
- const Chips({super.key});
- @override
- State<Chips> createState() => _ChipsState();
- }
- class _ChipsState extends State<Chips> {
- bool isFiltered = true;
- @override
- Widget build(BuildContext context) {
- return ComponentDecoration(
- label: 'Chips',
- tooltipMessage:
- 'Use ActionChip, FilterChip, or InputChip. \nActionChip can also be used for suggestion chip',
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.center,
- children: <Widget>[
- Wrap(
- spacing: smallSpacing,
- runSpacing: smallSpacing,
- children: <Widget>[
- ActionChip(
- label: const Text('Assist'),
- avatar: const Icon(Icons.event),
- onPressed: () {},
- ),
- FilterChip(
- label: const Text('Filter'),
- selected: isFiltered,
- onSelected: (selected) {
- setState(() => isFiltered = selected);
- },
- ),
- InputChip(
- label: const Text('Input'),
- onPressed: () {},
- onDeleted: () {},
- ),
- ActionChip(
- label: const Text('Suggestion'),
- onPressed: () {},
- ),
- ],
- ),
- colDivider,
- Wrap(
- spacing: smallSpacing,
- runSpacing: smallSpacing,
- children: <Widget>[
- const ActionChip(
- label: Text('Assist'),
- avatar: Icon(Icons.event),
- ),
- FilterChip(
- label: const Text('Filter'),
- selected: isFiltered,
- onSelected: null,
- ),
- InputChip(
- label: const Text('Input'),
- onDeleted: () {},
- isEnabled: false,
- ),
- const ActionChip(
- label: Text('Suggestion'),
- ),
- ],
- ),
- ],
- ),
- );
- }
- }
- class SegmentedButtons extends StatelessWidget {
- const SegmentedButtons({super.key});
- @override
- Widget build(BuildContext context) {
- return ComponentDecoration(
- label: 'Segmented buttons',
- tooltipMessage: 'Use SegmentedButton<T>',
- child: Column(
- children: const <Widget>[
- SingleChoice(),
- colDivider,
- MultipleChoice(),
- ],
- ),
- );
- }
- }
- enum Calendar { day, week, month, year }
- class SingleChoice extends StatefulWidget {
- const SingleChoice({super.key});
- @override
- State<SingleChoice> createState() => _SingleChoiceState();
- }
- class _SingleChoiceState extends State<SingleChoice> {
- Calendar calendarView = Calendar.day;
- @override
- Widget build(BuildContext context) {
- return SegmentedButton<Calendar>(
- segments: const <ButtonSegment<Calendar>>[
- ButtonSegment<Calendar>(
- value: Calendar.day,
- label: Text('Day'),
- icon: Icon(Icons.calendar_view_day)),
- ButtonSegment<Calendar>(
- value: Calendar.week,
- label: Text('Week'),
- icon: Icon(Icons.calendar_view_week)),
- ButtonSegment<Calendar>(
- value: Calendar.month,
- label: Text('Month'),
- icon: Icon(Icons.calendar_view_month)),
- ButtonSegment<Calendar>(
- value: Calendar.year,
- label: Text('Year'),
- icon: Icon(Icons.calendar_today)),
- ],
- selected: <Calendar>{calendarView},
- onSelectionChanged: (newSelection) {
- setState(() {
- // By default there is only a single segment that can be
- // selected at one time, so its value is always the first
- // item in the selected set.
- calendarView = newSelection.first;
- });
- },
- );
- }
- }
- enum Sizes { extraSmall, small, medium, large, extraLarge }
- class MultipleChoice extends StatefulWidget {
- const MultipleChoice({super.key});
- @override
- State<MultipleChoice> createState() => _MultipleChoiceState();
- }
- class _MultipleChoiceState extends State<MultipleChoice> {
- Set<Sizes> selection = <Sizes>{Sizes.large, Sizes.extraLarge};
- @override
- Widget build(BuildContext context) {
- return SegmentedButton<Sizes>(
- segments: const <ButtonSegment<Sizes>>[
- ButtonSegment<Sizes>(value: Sizes.extraSmall, label: Text('XS')),
- ButtonSegment<Sizes>(value: Sizes.small, label: Text('S')),
- ButtonSegment<Sizes>(value: Sizes.medium, label: Text('M')),
- ButtonSegment<Sizes>(
- value: Sizes.large,
- label: Text('L'),
- ),
- ButtonSegment<Sizes>(value: Sizes.extraLarge, label: Text('XL')),
- ],
- selected: selection,
- onSelectionChanged: (newSelection) {
- setState(() {
- selection = newSelection;
- });
- },
- multiSelectionEnabled: true,
- );
- }
- }
- class SnackBarSection extends StatelessWidget {
- const SnackBarSection({super.key});
- @override
- Widget build(BuildContext context) {
- return ComponentDecoration(
- label: 'Snackbar',
- tooltipMessage:
- 'Use ScaffoldMessenger.of(context).showSnackBar with SnackBar',
- child: TextButton(
- onPressed: () {
- final snackBar = SnackBar(
- behavior: SnackBarBehavior.floating,
- width: 400.0,
- content: const Text('This is a snackbar'),
- action: SnackBarAction(
- label: 'Close',
- onPressed: () {},
- ),
- );
- ScaffoldMessenger.of(context).hideCurrentSnackBar();
- ScaffoldMessenger.of(context).showSnackBar(snackBar);
- },
- child: const Text(
- 'Show snackbar',
- style: TextStyle(fontWeight: FontWeight.bold),
- ),
- ),
- );
- }
- }
- class BottomSheetSection extends StatefulWidget {
- const BottomSheetSection({super.key});
- @override
- State<BottomSheetSection> createState() => _BottomSheetSectionState();
- }
- class _BottomSheetSectionState extends State<BottomSheetSection> {
- bool isNonModalBottomSheetOpen = false;
- PersistentBottomSheetController<void>? _nonModalBottomSheetController;
- @override
- Widget build(BuildContext context) {
- List<Widget> buttonList = <Widget>[
- IconButton(onPressed: () {}, icon: const Icon(Icons.share_outlined)),
- IconButton(onPressed: () {}, icon: const Icon(Icons.add)),
- IconButton(onPressed: () {}, icon: const Icon(Icons.delete_outline)),
- IconButton(onPressed: () {}, icon: const Icon(Icons.archive_outlined)),
- IconButton(onPressed: () {}, icon: const Icon(Icons.settings_outlined)),
- IconButton(onPressed: () {}, icon: const Icon(Icons.favorite_border)),
- ];
- List<Text> labelList = const <Text>[
- Text('Share'),
- Text('Add to'),
- Text('Trash'),
- Text('Archive'),
- Text('Settings'),
- Text('Favorite')
- ];
- buttonList = List.generate(
- buttonList.length,
- (index) => Padding(
- padding: const EdgeInsets.fromLTRB(20.0, 30.0, 20.0, 20.0),
- child: Column(
- mainAxisAlignment: MainAxisAlignment.start,
- children: [
- buttonList[index],
- labelList[index],
- ],
- ),
- ));
- return ComponentDecoration(
- label: 'Bottom sheet',
- tooltipMessage: 'Use showModalBottomSheet<T> or showBottomSheet<T>',
- child: Wrap(
- alignment: WrapAlignment.spaceEvenly,
- children: [
- TextButton(
- child: const Text(
- 'Show modal bottom sheet',
- style: TextStyle(fontWeight: FontWeight.bold),
- ),
- onPressed: () {
- showModalBottomSheet<void>(
- context: context,
- // TODO: Remove when this is in the framework https://github.com/flutter/flutter/issues/118619
- constraints: const BoxConstraints(maxWidth: 640),
- builder: (context) {
- return SizedBox(
- height: 150,
- child: Padding(
- padding: const EdgeInsets.symmetric(horizontal: 32.0),
- child: ListView(
- shrinkWrap: true,
- scrollDirection: Axis.horizontal,
- children: buttonList,
- ),
- ),
- );
- },
- );
- },
- ),
- TextButton(
- child: Text(
- isNonModalBottomSheetOpen
- ? 'Hide bottom sheet'
- : 'Show bottom sheet',
- style: const TextStyle(fontWeight: FontWeight.bold),
- ),
- onPressed: () {
- if (isNonModalBottomSheetOpen) {
- _nonModalBottomSheetController?.close();
- setState(() {
- isNonModalBottomSheetOpen = false;
- });
- return;
- } else {
- setState(() {
- isNonModalBottomSheetOpen = true;
- });
- }
- _nonModalBottomSheetController = showBottomSheet<void>(
- elevation: 8.0,
- context: context,
- // TODO: Remove when this is in the framework https://github.com/flutter/flutter/issues/118619
- constraints: const BoxConstraints(maxWidth: 640),
- builder: (context) {
- return SizedBox(
- height: 150,
- child: Padding(
- padding: const EdgeInsets.symmetric(horizontal: 32.0),
- child: ListView(
- shrinkWrap: true,
- scrollDirection: Axis.horizontal,
- children: buttonList,
- ),
- ),
- );
- },
- );
- },
- ),
- ],
- ),
- );
- }
- }
- class BottomAppBars extends StatelessWidget {
- const BottomAppBars({super.key});
- @override
- Widget build(BuildContext context) {
- return ComponentDecoration(
- label: 'Bottom app bar',
- tooltipMessage: 'Use BottomAppBar',
- child: Column(
- children: [
- SizedBox(
- height: 80,
- child: Scaffold(
- floatingActionButton: FloatingActionButton(
- onPressed: () {},
- elevation: 0.0,
- child: const Icon(Icons.add),
- ),
- floatingActionButtonLocation:
- FloatingActionButtonLocation.endContained,
- bottomNavigationBar: BottomAppBar(
- child: Row(
- children: <Widget>[
- const IconButtonAnchorExample(),
- IconButton(
- tooltip: 'Search',
- icon: const Icon(Icons.search),
- onPressed: () {},
- ),
- IconButton(
- tooltip: 'Favorite',
- icon: const Icon(Icons.favorite),
- onPressed: () {},
- ),
- ],
- ),
- ),
- ),
- ),
- ],
- ),
- );
- }
- }
- class IconButtonAnchorExample extends StatelessWidget {
- const IconButtonAnchorExample({super.key});
- @override
- Widget build(BuildContext context) {
- return MenuAnchor(
- builder: (context, controller, child) {
- return IconButton(
- onPressed: () {
- if (controller.isOpen) {
- controller.close();
- } else {
- controller.open();
- }
- },
- icon: const Icon(Icons.more_vert),
- );
- },
- menuChildren: [
- MenuItemButton(
- child: const Text('Menu 1'),
- onPressed: () {},
- ),
- MenuItemButton(
- child: const Text('Menu 2'),
- onPressed: () {},
- ),
- SubmenuButton(
- menuChildren: <Widget>[
- MenuItemButton(
- onPressed: () {},
- child: const Text('Menu 3.1'),
- ),
- MenuItemButton(
- onPressed: () {},
- child: const Text('Menu 3.2'),
- ),
- MenuItemButton(
- onPressed: () {},
- child: const Text('Menu 3.3'),
- ),
- ],
- child: const Text('Menu 3'),
- ),
- ],
- );
- }
- }
- class ButtonAnchorExample extends StatelessWidget {
- const ButtonAnchorExample({super.key});
- @override
- Widget build(BuildContext context) {
- return MenuAnchor(
- builder: (context, controller, child) {
- return FilledButton.tonal(
- onPressed: () {
- if (controller.isOpen) {
- controller.close();
- } else {
- controller.open();
- }
- },
- child: const Text('Show menu'),
- );
- },
- menuChildren: [
- MenuItemButton(
- leadingIcon: const Icon(Icons.people_alt_outlined),
- child: const Text('Item 1'),
- onPressed: () {},
- ),
- MenuItemButton(
- leadingIcon: const Icon(Icons.remove_red_eye_outlined),
- child: const Text('Item 2'),
- onPressed: () {},
- ),
- MenuItemButton(
- leadingIcon: const Icon(Icons.refresh),
- onPressed: () {},
- child: const Text('Item 3'),
- ),
- ],
- );
- }
- }
- class NavigationDrawers extends StatelessWidget {
- const NavigationDrawers({super.key, required this.scaffoldKey});
- final GlobalKey<ScaffoldState> scaffoldKey;
- @override
- Widget build(BuildContext context) {
- return ComponentDecoration(
- label: 'Navigation drawer',
- tooltipMessage:
- 'Use NavigationDrawer. For modal navigation drawers, see Scaffold.endDrawer',
- child: Column(
- children: [
- const SizedBox(height: 520, child: NavigationDrawerSection()),
- colDivider,
- colDivider,
- TextButton(
- child: const Text('Show modal navigation drawer',
- style: TextStyle(fontWeight: FontWeight.bold)),
- onPressed: () {
- scaffoldKey.currentState!.openEndDrawer();
- },
- ),
- ],
- ),
- );
- }
- }
- class NavigationDrawerSection extends StatefulWidget {
- const NavigationDrawerSection({super.key});
- @override
- State<NavigationDrawerSection> createState() =>
- _NavigationDrawerSectionState();
- }
- class _NavigationDrawerSectionState extends State<NavigationDrawerSection> {
- int navDrawerIndex = 0;
- @override
- Widget build(BuildContext context) {
- return NavigationDrawer(
- onDestinationSelected: (selectedIndex) {
- setState(() {
- navDrawerIndex = selectedIndex;
- });
- },
- selectedIndex: navDrawerIndex,
- children: <Widget>[
- Padding(
- padding: const EdgeInsets.fromLTRB(28, 16, 16, 10),
- child: Text(
- 'Mail',
- style: Theme.of(context).textTheme.titleSmall,
- ),
- ),
- ...destinations.map((destination) {
- return NavigationDrawerDestination(
- label: Text(destination.label),
- icon: destination.icon,
- selectedIcon: destination.selectedIcon,
- );
- }),
- const Divider(indent: 28, endIndent: 28),
- Padding(
- padding: const EdgeInsets.fromLTRB(28, 16, 16, 10),
- child: Text(
- 'Labels',
- style: Theme.of(context).textTheme.titleSmall,
- ),
- ),
- ...labelDestinations.map((destination) {
- return NavigationDrawerDestination(
- label: Text(destination.label),
- icon: destination.icon,
- selectedIcon: destination.selectedIcon,
- );
- }),
- ],
- );
- }
- }
- class ExampleDestination {
- const ExampleDestination(this.label, this.icon, this.selectedIcon);
- final String label;
- final Widget icon;
- final Widget selectedIcon;
- }
- const List<ExampleDestination> destinations = <ExampleDestination>[
- ExampleDestination('Inbox', Icon(Icons.inbox_outlined), Icon(Icons.inbox)),
- ExampleDestination('Outbox', Icon(Icons.send_outlined), Icon(Icons.send)),
- ExampleDestination(
- 'Favorites', Icon(Icons.favorite_outline), Icon(Icons.favorite)),
- ExampleDestination('Trash', Icon(Icons.delete_outline), Icon(Icons.delete)),
- ];
- const List<ExampleDestination> labelDestinations = <ExampleDestination>[
- ExampleDestination(
- 'Family', Icon(Icons.bookmark_border), Icon(Icons.bookmark)),
- ExampleDestination(
- 'School', Icon(Icons.bookmark_border), Icon(Icons.bookmark)),
- ExampleDestination('Work', Icon(Icons.bookmark_border), Icon(Icons.bookmark)),
- ];
- class NavigationRails extends StatelessWidget {
- const NavigationRails({super.key});
- @override
- Widget build(BuildContext context) {
- return const ComponentDecoration(
- label: 'Navigation rail',
- tooltipMessage: 'Use NavigationRail',
- child: IntrinsicWidth(
- child: SizedBox(height: 420, child: NavigationRailSection())),
- );
- }
- }
- class NavigationRailSection extends StatefulWidget {
- const NavigationRailSection({super.key});
- @override
- State<NavigationRailSection> createState() => _NavigationRailSectionState();
- }
- class _NavigationRailSectionState extends State<NavigationRailSection> {
- int navRailIndex = 0;
- @override
- Widget build(BuildContext context) {
- return NavigationRail(
- onDestinationSelected: (selectedIndex) {
- setState(() {
- navRailIndex = selectedIndex;
- });
- },
- elevation: 4,
- leading: FloatingActionButton(
- child: const Icon(Icons.create), onPressed: () {}),
- groupAlignment: 0.0,
- selectedIndex: navRailIndex,
- labelType: NavigationRailLabelType.selected,
- destinations: <NavigationRailDestination>[
- ...destinations.map((destination) {
- return NavigationRailDestination(
- label: Text(destination.label),
- icon: destination.icon,
- selectedIcon: destination.selectedIcon,
- );
- }),
- ],
- );
- }
- }
- class Tabs extends StatefulWidget {
- const Tabs({super.key});
- @override
- State<Tabs> createState() => _TabsState();
- }
- class _TabsState extends State<Tabs> with TickerProviderStateMixin {
- late TabController _tabController;
- @override
- void initState() {
- super.initState();
- _tabController = TabController(length: 3, vsync: this);
- }
- @override
- Widget build(BuildContext context) {
- return ComponentDecoration(
- label: 'Tabs',
- tooltipMessage: 'Use TabBar',
- child: SizedBox(
- height: 80,
- child: Scaffold(
- appBar: AppBar(
- bottom: TabBar(
- controller: _tabController,
- tabs: const <Widget>[
- Tab(
- icon: Icon(Icons.videocam_outlined),
- text: 'Video',
- iconMargin: EdgeInsets.only(bottom: 0.0),
- ),
- Tab(
- icon: Icon(Icons.photo_outlined),
- text: 'Photos',
- iconMargin: EdgeInsets.only(bottom: 0.0),
- ),
- Tab(
- icon: Icon(Icons.audiotrack_sharp),
- text: 'Audio',
- iconMargin: EdgeInsets.only(bottom: 0.0),
- ),
- ],
- ),
- // TODO: Showcase secondary tab bar https://github.com/flutter/flutter/issues/111962
- ),
- ),
- ),
- );
- }
- }
- class TopAppBars extends StatelessWidget {
- const TopAppBars({super.key});
- static final actions = [
- IconButton(icon: const Icon(Icons.attach_file), onPressed: () {}),
- IconButton(icon: const Icon(Icons.event), onPressed: () {}),
- IconButton(icon: const Icon(Icons.more_vert), onPressed: () {}),
- ];
- @override
- Widget build(BuildContext context) {
- return ComponentDecoration(
- label: 'Top app bars',
- tooltipMessage:
- 'Use AppBar, SliverAppBar, SliverAppBar.medium, or SliverAppBar.large',
- child: Column(
- children: [
- AppBar(
- title: const Text('Center-aligned'),
- leading: const BackButton(),
- actions: [
- IconButton(
- iconSize: 32,
- icon: const Icon(Icons.account_circle_outlined),
- onPressed: () {},
- ),
- ],
- centerTitle: true,
- ),
- colDivider,
- AppBar(
- title: const Text('Small'),
- leading: const BackButton(),
- actions: actions,
- centerTitle: false,
- ),
- colDivider,
- SizedBox(
- height: 100,
- child: CustomScrollView(
- slivers: [
- SliverAppBar.medium(
- title: const Text('Medium'),
- leading: const BackButton(),
- actions: actions,
- ),
- const SliverFillRemaining(),
- ],
- ),
- ),
- colDivider,
- SizedBox(
- height: 130,
- child: CustomScrollView(
- slivers: [
- SliverAppBar.large(
- title: const Text('Large'),
- leading: const BackButton(),
- actions: actions,
- ),
- const SliverFillRemaining(),
- ],
- ),
- ),
- ],
- ),
- );
- }
- }
- class Menus extends StatefulWidget {
- const Menus({super.key});
- @override
- State<Menus> createState() => _MenusState();
- }
- class _MenusState extends State<Menus> {
- final TextEditingController colorController = TextEditingController();
- final TextEditingController iconController = TextEditingController();
- IconLabel? selectedIcon = IconLabel.smile;
- ColorLabel? selectedColor;
- @override
- Widget build(BuildContext context) {
- final List<DropdownMenuEntry<ColorLabel>> colorEntries =
- <DropdownMenuEntry<ColorLabel>>[];
- for (final ColorLabel color in ColorLabel.values) {
- colorEntries.add(DropdownMenuEntry<ColorLabel>(
- value: color, label: color.label, enabled: color.label != 'Grey'));
- }
- final List<DropdownMenuEntry<IconLabel>> iconEntries =
- <DropdownMenuEntry<IconLabel>>[];
- for (final IconLabel icon in IconLabel.values) {
- iconEntries
- .add(DropdownMenuEntry<IconLabel>(value: icon, label: icon.label));
- }
- return ComponentDecoration(
- label: 'Menus',
- tooltipMessage: 'Use MenuAnchor or DropdownMenu<T>',
- child: Column(
- children: [
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: const <Widget>[
- ButtonAnchorExample(),
- rowDivider,
- IconButtonAnchorExample(),
- ],
- ),
- colDivider,
- Wrap(
- alignment: WrapAlignment.spaceAround,
- runAlignment: WrapAlignment.center,
- crossAxisAlignment: WrapCrossAlignment.center,
- spacing: smallSpacing,
- runSpacing: smallSpacing,
- children: [
- DropdownMenu<ColorLabel>(
- controller: colorController,
- label: const Text('Color'),
- enableFilter: true,
- dropdownMenuEntries: colorEntries,
- inputDecorationTheme: const InputDecorationTheme(filled: true),
- onSelected: (color) {
- setState(() {
- selectedColor = color;
- });
- },
- ),
- DropdownMenu<IconLabel>(
- initialSelection: IconLabel.smile,
- controller: iconController,
- leadingIcon: const Icon(Icons.search),
- label: const Text('Icon'),
- dropdownMenuEntries: iconEntries,
- onSelected: (icon) {
- setState(() {
- selectedIcon = icon;
- });
- },
- ),
- Icon(
- selectedIcon?.icon,
- color: selectedColor?.color ?? Colors.grey.withOpacity(0.5),
- )
- ],
- ),
- ],
- ),
- );
- }
- }
- enum ColorLabel {
- blue('Blue', Colors.blue),
- pink('Pink', Colors.pink),
- green('Green', Colors.green),
- yellow('Yellow', Colors.yellow),
- grey('Grey', Colors.grey);
- const ColorLabel(this.label, this.color);
- final String label;
- final Color color;
- }
- enum IconLabel {
- smile('Smile', Icons.sentiment_satisfied_outlined),
- cloud(
- 'Cloud',
- Icons.cloud_outlined,
- ),
- brush('Brush', Icons.brush_outlined),
- heart('Heart', Icons.favorite);
- const IconLabel(this.label, this.icon);
- final String label;
- final IconData icon;
- }
- class Sliders extends StatefulWidget {
- const Sliders({super.key});
- @override
- State<Sliders> createState() => _SlidersState();
- }
- class _SlidersState extends State<Sliders> {
- double sliderValue0 = 30.0;
- double sliderValue1 = 20.0;
- @override
- Widget build(BuildContext context) {
- return ComponentDecoration(
- label: 'Sliders',
- tooltipMessage: 'Use Slider or RangeSlider',
- child: Column(
- children: <Widget>[
- Slider(
- max: 100,
- value: sliderValue0,
- onChanged: (value) {
- setState(() {
- sliderValue0 = value;
- });
- },
- ),
- const SizedBox(height: 20),
- Slider(
- max: 100,
- divisions: 5,
- value: sliderValue1,
- label: sliderValue1.round().toString(),
- onChanged: (value) {
- setState(() {
- sliderValue1 = value;
- });
- },
- ),
- ],
- ));
- }
- }
- class ComponentDecoration extends StatefulWidget {
- const ComponentDecoration({
- super.key,
- required this.label,
- required this.child,
- this.tooltipMessage = '',
- });
- final String label;
- final Widget child;
- final String? tooltipMessage;
- @override
- State<ComponentDecoration> createState() => _ComponentDecorationState();
- }
- class _ComponentDecorationState extends State<ComponentDecoration> {
- final focusNode = FocusNode();
- @override
- Widget build(BuildContext context) {
- return RepaintBoundary(
- child: Padding(
- padding: const EdgeInsets.symmetric(vertical: smallSpacing),
- child: Column(
- children: [
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- Text(widget.label,
- style: Theme.of(context).textTheme.titleSmall),
- Tooltip(
- message: widget.tooltipMessage,
- child: const Padding(
- padding: EdgeInsets.symmetric(horizontal: 5.0),
- child: Icon(Icons.info_outline, size: 16)),
- ),
- ],
- ),
- ConstrainedBox(
- constraints:
- const BoxConstraints.tightFor(width: widthConstraint),
- // Tapping within the a component card should request focus
- // for that component's children.
- child: Focus(
- focusNode: focusNode,
- canRequestFocus: true,
- child: GestureDetector(
- onTapDown: (_) {
- focusNode.requestFocus();
- },
- behavior: HitTestBehavior.opaque,
- child: Card(
- elevation: 0,
- shape: RoundedRectangleBorder(
- side: BorderSide(
- color: Theme.of(context).colorScheme.outlineVariant,
- ),
- borderRadius: const BorderRadius.all(Radius.circular(12)),
- ),
- child: Padding(
- padding: const EdgeInsets.symmetric(
- horizontal: 5.0, vertical: 20.0),
- child: Center(
- child: widget.child,
- ),
- ),
- ),
- ),
- ),
- ),
- ],
- ),
- ),
- );
- }
- }
- class ComponentGroupDecoration extends StatelessWidget {
- const ComponentGroupDecoration(
- {super.key, required this.label, required this.children});
- final String label;
- final List<Widget> children;
- @override
- Widget build(BuildContext context) {
- // Fully traverse this component group before moving on
- return FocusTraversalGroup(
- child: Card(
- margin: EdgeInsets.zero,
- elevation: 0,
- color: Theme.of(context).colorScheme.surfaceVariant.withOpacity(0.3),
- child: Padding(
- padding: const EdgeInsets.symmetric(vertical: 20.0),
- child: Center(
- child: Column(
- children: [
- Text(label, style: Theme.of(context).textTheme.titleLarge),
- colDivider,
- ...children
- ],
- ),
- ),
- ),
- ),
- );
- }
- }
|