Instantly share code, notes, and snippets.
Created
September 25, 2020 00:49
-
Save HansMuller/e560e1c2e4455ad53aac245079ccdcf2 to your computer and use it in GitHub Desktop.
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
import 'package:flutter/material.dart'; | |
class DialogButtons extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
void dismissDialog() { | |
Navigator.of(context).pop(); | |
} | |
void showDemoDialog(String message, ButtonStyle style1, [ButtonStyle style2]) { | |
showDialog( | |
context: context, | |
builder: (BuildContext context) { | |
return AlertDialog( | |
title: Text('AlertDialog Title'), | |
content: Text(message), | |
actions: <Widget>[ | |
OutlinedButton( | |
style: style1, | |
onPressed: () { dismissDialog(); }, | |
child: Text('Approve'), | |
), | |
OutlinedButton( | |
style: style2 ?? style1, | |
onPressed: () { dismissDialog(); }, | |
child: Text('Really Approve'), | |
), | |
], | |
); | |
}, | |
); | |
} | |
return Center( | |
child: Column( | |
mainAxisSize: MainAxisSize.min, | |
children: <Widget>[ | |
ElevatedButton( | |
onPressed: () { | |
showDemoDialog( | |
'Stadium shaped action buttons, default ouline.', | |
OutlinedButton.styleFrom(shape: StadiumBorder()), | |
); | |
}, | |
child: Text('Show an AlertDialog'), | |
), | |
SizedBox(height: 16), | |
ElevatedButton( | |
onPressed: () { | |
showDemoDialog( | |
'One Stadium shaped action button, with a heavy, primary color ' | |
'outline.', | |
OutlinedButton.styleFrom(shape: StadiumBorder()), | |
OutlinedButton.styleFrom( | |
shape: StadiumBorder(), | |
side: BorderSide( | |
width: 2, | |
color: Theme.of(context).colorScheme.primary, | |
), | |
), | |
); | |
}, | |
child: Text('Show another AlertDialog'), | |
), | |
SizedBox(height: 16), | |
ElevatedButton( | |
onPressed: () { | |
showDemoDialog( | |
'Stadium shaped action buttons, with a heavy, primary color ' | |
'outline when the button is focused or hovered', | |
OutlinedButton.styleFrom( | |
shape: StadiumBorder(), | |
).copyWith( | |
side: MaterialStateProperty.resolveWith<BorderSide>((Set<MaterialState> states) { | |
if (states.contains(MaterialState.hovered) || states.contains(MaterialState.focused)) { | |
return BorderSide( | |
width: 2, | |
color: Theme.of(context).colorScheme.primary, | |
); | |
} | |
return null; // defer to the default | |
}, | |
)), | |
); | |
}, | |
child: Text('Show yet another AlertDialog'), | |
), | |
] | |
), | |
); | |
} | |
} | |
class IndividuallySizedButtons extends StatefulWidget { | |
@override | |
_IndividuallySizedButtonsState createState() => _IndividuallySizedButtonsState(); | |
} | |
class _IndividuallySizedButtonsState extends State<IndividuallySizedButtons> { | |
bool _textButtonFlag = false; | |
bool _containedButtonFlag = false; | |
bool _outlinedButtonFlag = false; | |
@override | |
Widget build(BuildContext context) { | |
final TextTheme textTheme = Theme.of(context).textTheme; | |
const Widget spacer = SizedBox(height: 16); | |
return SingleChildScrollView( | |
child: Column( | |
mainAxisSize: MainAxisSize.min, | |
children: <Widget>[ | |
spacer, | |
TextButton( | |
style: TextButton.styleFrom( | |
textStyle: _textButtonFlag ? textTheme.headline2 : textTheme.headline4, | |
), | |
onPressed: () { | |
setState(() { | |
_textButtonFlag = !_textButtonFlag; | |
}); | |
}, | |
child: Text('TEXT'), | |
), | |
spacer, | |
ElevatedButton( | |
style: ElevatedButton.styleFrom( | |
textStyle: _containedButtonFlag ? textTheme.headline2 : textTheme.headline4, | |
), | |
onPressed: () { | |
setState(() { | |
_containedButtonFlag = !_containedButtonFlag; | |
}); | |
}, | |
child: Text('CONTAINED'), | |
), | |
spacer, | |
OutlinedButton( | |
style: OutlinedButton.styleFrom( | |
textStyle: _outlinedButtonFlag ? textTheme.headline2 : textTheme.headline4, | |
), | |
onPressed: () { | |
setState(() { | |
_outlinedButtonFlag = !_outlinedButtonFlag; | |
}); | |
}, | |
child: Text('OUTLINED'), | |
), | |
spacer, | |
], | |
), | |
); | |
} | |
} | |
class ShapeButtons extends StatefulWidget { | |
@override | |
_ShapeButtonsState createState() => _ShapeButtonsState(); | |
} | |
class _ShapeButtonsState extends State<ShapeButtons> { | |
int shapeIndex = 0; | |
@override | |
Widget build(BuildContext context) { | |
final List<ShapeBorder> buttonShapes = <ShapeBorder>[ | |
RoundedRectangleBorder( | |
borderRadius: BorderRadius.all(Radius.circular(4)), | |
), | |
BeveledRectangleBorder( | |
borderRadius: BorderRadius.all(Radius.circular(8)), | |
), | |
StadiumBorder(), | |
]; | |
return TextButtonTheme( | |
data: TextButtonThemeData( | |
style: TextButton.styleFrom(shape: buttonShapes[shapeIndex]), | |
), | |
child: ElevatedButtonTheme( | |
data: ElevatedButtonThemeData( | |
style: ElevatedButton.styleFrom(shape: buttonShapes[shapeIndex]), | |
), | |
child: OutlinedButtonTheme( | |
data: OutlinedButtonThemeData( | |
style: OutlinedButton.styleFrom(shape: buttonShapes[shapeIndex]), | |
), | |
child: OverflowBox( | |
maxWidth: double.infinity, | |
child: DefaultButtons( | |
onPressed: () { | |
setState(() { | |
shapeIndex = (shapeIndex + 1) % buttonShapes.length; | |
}); | |
}, | |
), | |
), | |
), | |
), | |
); | |
} | |
} | |
class TextStyleButtons extends StatefulWidget { | |
@override | |
_TextStyleButtonsState createState() => _TextStyleButtonsState(); | |
} | |
class _TextStyleButtonsState extends State<TextStyleButtons> { | |
bool _flag = false; | |
@override | |
Widget build(BuildContext context) { | |
final TextTheme textTheme = Theme.of(context).textTheme; | |
final TextStyle style = _flag ? textTheme.headline1 : textTheme.headline4; | |
return TextButtonTheme( | |
data: TextButtonThemeData( | |
style: TextButton.styleFrom(textStyle: style), | |
), | |
child: ElevatedButtonTheme( | |
data: ElevatedButtonThemeData( | |
style: ElevatedButton.styleFrom(textStyle: style), | |
), | |
child: OutlinedButtonTheme( | |
data: OutlinedButtonThemeData( | |
style: OutlinedButton.styleFrom(textStyle: style), | |
), | |
child: OverflowBox( | |
maxWidth: double.infinity, | |
child: DefaultButtons( | |
iconSize: _flag ? 64 : 24, | |
onPressed: () { | |
setState(() { | |
_flag = !_flag; | |
}); | |
}, | |
), | |
), | |
), | |
), | |
); | |
} | |
} | |
class TextColorButtons extends StatefulWidget { | |
@override | |
_TextColorButtonsState createState() => _TextColorButtonsState(); | |
} | |
class _TextColorButtonsState extends State<TextColorButtons> { | |
int index = 0; | |
static const List<Color> foregroundColors = <Color>[ | |
Colors.red, | |
Colors.purple, | |
Colors.indigo, | |
Colors.teal, | |
Colors.lime, | |
Colors.deepOrange, | |
Colors.yellow, | |
]; | |
static const List<Color> backgroundColors = <Color>[ | |
Colors.lightBlue, | |
Colors.yellow, | |
Colors.grey, | |
Colors.amber, | |
Colors.orange, | |
Colors.blue, | |
Colors.purple, | |
]; | |
@override | |
Widget build(BuildContext context) { | |
final Color foregroundColor = foregroundColors[index]; | |
final Color backgroundColor = backgroundColors[index]; | |
return TextButtonTheme( | |
data: TextButtonThemeData( | |
style: TextButton.styleFrom(primary: foregroundColor), | |
), | |
child: ElevatedButtonTheme( | |
data: ElevatedButtonThemeData( | |
style: ElevatedButton.styleFrom( | |
primary: backgroundColor, | |
onPrimary: foregroundColor, | |
), | |
), | |
child: OutlinedButtonTheme( | |
data: OutlinedButtonThemeData( | |
style: TextButton.styleFrom(primary: foregroundColor), | |
), | |
child: DefaultButtons( | |
onPressed: () { | |
setState(() { | |
index = (index + 1) % foregroundColors.length; | |
}); | |
}, | |
), | |
), | |
), | |
); | |
} | |
} | |
class DefaultButtons extends StatelessWidget { | |
const DefaultButtons({ Key key, this.onPressed, this.iconSize = 18 }) : super(key: key); | |
final VoidCallback onPressed; | |
final double iconSize; | |
@override | |
Widget build(BuildContext context) { | |
const Widget spacer = SizedBox(height: 4); | |
final Widget icon = Icon(Icons.star, size: iconSize); | |
return SingleChildScrollView( | |
child: Column( | |
mainAxisSize: MainAxisSize.min, | |
children: <Widget>[ | |
TextButton( | |
onPressed: onPressed ?? () { }, | |
child: Text('TEXT'), | |
), | |
spacer, | |
TextButton.icon( | |
onPressed: onPressed ?? () { }, | |
icon: icon, | |
label: Text('TEXT'), | |
), | |
spacer, | |
TextButton.icon( | |
onPressed: null, | |
icon: icon, | |
label: Text('DISABLED'), | |
), | |
spacer, | |
ElevatedButton( | |
onPressed: onPressed ?? () { }, | |
child: Text('CONTAINED'), | |
), | |
spacer, | |
ElevatedButton.icon( | |
onPressed: onPressed ?? () { }, | |
icon: icon, | |
label: Text('CONTAINED'), | |
), | |
spacer, | |
ElevatedButton.icon( | |
onPressed: null, | |
icon: icon, | |
label: Text('DISABLED'), | |
), | |
spacer, | |
OutlinedButton( | |
onPressed: onPressed ?? () { }, | |
child: Text('OUTLINED'), | |
), | |
OutlinedButton.icon( | |
onPressed: onPressed ?? () { }, | |
icon: icon, | |
label: Text('OUTLINED'), | |
), | |
spacer, | |
OutlinedButton.icon( | |
onPressed: null, | |
icon: icon, | |
label: Text('DISABLED'), | |
), | |
spacer, | |
], | |
), | |
); | |
} | |
} | |
class ButtonDemo { | |
const ButtonDemo({ Key key, this.title, this.description, this.builder }); | |
final String title; | |
final String description; | |
final WidgetBuilder builder; | |
} | |
final List<ButtonDemo> allButtonDemos = <ButtonDemo>[ | |
ButtonDemo( | |
title: 'Default Buttons', | |
description: 'Enabled and disabled buttons in their default configurations.', | |
builder: (BuildContext context) => DefaultButtons(), | |
), | |
ButtonDemo( | |
title: 'TextColor Buttons', | |
description: | |
'Use TextButtonTheme, ElevatedButtonTheme, OutlinedButtonTheme to ' | |
'override the text color of all buttons. The background color for ' | |
'ElevatedButtons does not change.', | |
builder: (BuildContext context) => TextColorButtons(), | |
), | |
ButtonDemo( | |
title: 'TextStyle Buttons', | |
description: | |
'Use TextButtonTheme, ElevatedButtonTheme, OutlinedButtonTheme to override ' | |
'the default text style of the buttons. Press any button to toggle the text ' | |
'style size to an even bigger value.', | |
builder: (BuildContext context) => TextStyleButtons(), | |
), | |
ButtonDemo( | |
title: 'Individually Sized Buttons', | |
description: | |
'Sets the ButtonStyle parameter of individual buttons to override their ' | |
'default text style/ Press any button to toggle its text text style size.', | |
builder: (BuildContext context) => IndividuallySizedButtons(), | |
), | |
ButtonDemo( | |
title: 'Button Shapes', | |
description: | |
'Use TextButtonTheme, ElevatedButtonTheme, OutlinedButtonTheme to ' | |
'override the shape all buttons.', | |
builder: (BuildContext context) => ShapeButtons(), | |
), | |
ButtonDemo( | |
title: 'Dialog Buttons', | |
description: | |
'Use ButtonStyle to configure the shape of a dialog\'s action buttons.', | |
builder: (BuildContext context) => DialogButtons(), | |
), | |
]; | |
class Home extends StatefulWidget { | |
const Home({ Key key, this.toggleThemeMode }) : super(key: key); | |
final VoidCallback toggleThemeMode; | |
@override | |
_HomeState createState() => _HomeState(); | |
} | |
class _HomeState extends State<Home> { | |
PageController _pageController; | |
int _currentPage = 0; | |
@override | |
void initState() { | |
super.initState(); | |
_pageController = PageController(initialPage: _currentPage); | |
_pageController.addListener(pageChanged); | |
} | |
@override | |
void dispose() { | |
_pageController.dispose(); | |
super.dispose(); | |
} | |
void pageChanged() { | |
if (_pageController.hasClients) { | |
setState(() { | |
_currentPage = _pageController.page.floor(); | |
}); | |
} | |
} | |
void changePage(int delta) { | |
if (_pageController.hasClients) { | |
const Duration duration = Duration(milliseconds: 300); | |
_pageController.animateToPage(_currentPage + delta, duration: duration, curve: Curves.easeInOut); | |
} | |
} | |
@override | |
Widget build(BuildContext context) { | |
final ColorScheme colorScheme = Theme.of(context).colorScheme; | |
final ButtonStyle actionButtonStyle = TextButton.styleFrom( | |
primary: colorScheme.onPrimary, | |
); | |
return Scaffold( | |
appBar: AppBar( | |
title: Text( | |
allButtonDemos[_currentPage].title, | |
style: TextStyle(color: colorScheme.onPrimary) | |
), | |
backgroundColor: colorScheme.primary, | |
actions: <Widget>[ | |
TextButton( | |
style: actionButtonStyle, | |
onPressed: widget.toggleThemeMode, | |
child: Icon(Icons.stars), | |
), | |
TextButton( | |
style: actionButtonStyle, | |
onPressed: () { changePage(-1); }, | |
child: Icon(Icons.arrow_back), | |
), | |
TextButton( | |
style: actionButtonStyle, | |
onPressed: () { changePage(1); }, | |
child: Icon(Icons.arrow_forward), | |
), | |
], | |
), | |
body: Column( | |
children: <Widget>[ | |
Padding( | |
padding: EdgeInsets.only(top: 16, left: 16, right: 16, bottom: 8), | |
child: Container( | |
height: 98, | |
color: colorScheme.onSurface.withOpacity(0.1), | |
alignment: Alignment.center, | |
child: Padding( | |
padding: EdgeInsets.all(12), | |
child: Text( | |
allButtonDemos[_currentPage].description, | |
maxLines: 4, | |
style: TextStyle(color: colorScheme.onSurface.withOpacity(0.7)), | |
), | |
), | |
), | |
), | |
Expanded( | |
child: PageView.builder( | |
controller: _pageController, | |
itemCount: allButtonDemos.length, | |
itemBuilder: (BuildContext context, int index) { | |
return allButtonDemos[index].builder(context); | |
}, | |
), | |
), | |
], | |
), | |
); | |
} | |
} | |
class App extends StatefulWidget { | |
@override | |
_AppState createState() => _AppState(); | |
} | |
class _AppState extends State<App> { | |
ThemeMode _themeMode = ThemeMode.light; | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
theme: ThemeData.from(colorScheme: ColorScheme.light()), | |
darkTheme: ThemeData.from(colorScheme: ColorScheme.dark()), | |
themeMode: _themeMode, | |
debugShowCheckedModeBanner: false, | |
home: Home( | |
toggleThemeMode: () { | |
setState(() { | |
_themeMode = _themeMode == ThemeMode.light ? ThemeMode.dark : ThemeMode.light; | |
}); | |
} | |
), | |
); | |
} | |
} | |
void main() { | |
runApp(App()); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment