How to Create Flutter Material3 Buttons from Scratch: A Beginner's Guide
Buttons are material3 components that provide the user a single tap facility for taking actions, making choices, submitting forms, saving data, opening a new page, etc.
Buttons are triggered when the user taps on them. They are the most commonly used feature provided in almost all the flutter apps.
import 'package:flutter/material.dart';
const _rowDivider = SizedBox(width: 10);
const _colDivider = SizedBox(height: 30);
void Function()? handlePressed(
BuildContext context, bool isDisabled, String buttonName) {
return isDisabled
? null
: () {
final snackBar = SnackBar(
content: Text(
'Yay! $buttonName is clicked!',
style: TextStyle(color: Theme.of(context).colorScheme.surface),
),
action: SnackBarAction(
textColor: Theme.of(context).colorScheme.surface,
label: 'Close',
onPressed: () {},
),
);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
};
}
class MaterialButtonRoute extends StatefulWidget {
const MaterialButtonRoute({super.key});
@override
MaterialButtonRouteState createState() => MaterialButtonRouteState();
}
class MaterialButtonRouteState extends State<MaterialButtonRoute> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
padding: const EdgeInsets.all(15),
scrollDirection: Axis.vertical,
child: Column(
children: <Widget>[
_colDivider,
Row(
children: const <Widget>[
Spacer(),
ButtonsWithoutIcon(isDisabled: true),
Spacer(),
ButtonsWithIcon(),
Spacer(),
ButtonsWithoutIcon(isDisabled: false),
Spacer(),
],
),
_colDivider,
Row(
children: const <Widget>[
Spacer(),
FloatingActionButtons(),
Spacer(),
],
),
],
),
),
);
}
}
class ButtonsWithoutIcon extends StatelessWidget {
final bool isDisabled;
const ButtonsWithoutIcon({super.key, required this.isDisabled});
@override
Widget build(BuildContext context) {
return
IntrinsicWidth(
child:
// Column to contain buttons
Column(
// Aligns all widgets in the column to stretch along the cross axis
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
// Elevated button
ElevatedButton(
// Calls the handlePressed function when the button is pressed
onPressed: handlePressed(context, isDisabled, "ElevatedButton"),
// Text to be displayed on the button
child: const Text("Elevated"),
),
// Vertical divider to separate buttons
_colDivider,
// Filled button
ElevatedButton(
// Defines the style of the button
style: ElevatedButton.styleFrom(
// Foreground color
foregroundColor: Theme.of(context).colorScheme.onPrimary, backgroundColor: Theme.of(context).colorScheme.primary,
).copyWith(elevation: ButtonStyleButton.allOrNull(0.0)),
// Calls the handlePressed function when the button is pressed
onPressed: handlePressed(context, isDisabled, "FilledButton"),
// Text to be displayed on the button
child: const Text('Filled'),
),
// Vertical divider to separate buttons
_colDivider,
// Filled tonal button
ElevatedButton(
// Defines the style of the button
style: ElevatedButton.styleFrom(
// Foreground color
foregroundColor: Theme.of(context).colorScheme.onSecondaryContainer, backgroundColor: Theme.of(context).colorScheme.secondaryContainer,
).copyWith(elevation: ButtonStyleButton.allOrNull(0.0)),
// Calls the handlePressed function when the button is pressed
onPressed: handlePressed(context, isDisabled, "FilledTonalButton"),
// Text to be displayed on the button
child: const Text('Filled Tonal'),
),
// Vertical divider to separate buttons
_colDivider,
// Outlined button
OutlinedButton(
// Calls the handlePressed function when the button is pressed
onPressed: handlePressed(context, isDisabled, "OutlinedButton"),
// Text to be displayed on the button
child: const Text("Outlined"),
),
// Vertical divider to separate buttons
_colDivider,
// Text button
TextButton(
// Calls the handlePressed function when the button is pressed
onPressed: handlePressed(context, isDisabled, "TextButton"),
// Text to be displayed on the button
child: const Text("Text")),
],
),
);
}
}
class ButtonsWithIcon extends StatelessWidget {
const ButtonsWithIcon({super.key});
@override
Widget build(BuildContext context) {
return IntrinsicWidth(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
ElevatedButton.icon(
onPressed:
handlePressed(context, false, "ElevatedButton with Icon"),
icon: const Icon(Icons.add),
label: const Text("Icon"),
),
_colDivider,
ElevatedButton.icon(
style: ElevatedButton.styleFrom(
// Foreground color
foregroundColor: Theme.of(context).colorScheme.onPrimary, backgroundColor: Theme.of(context).colorScheme.primary,
).copyWith(elevation: ButtonStyleButton.allOrNull(0.0)),
onPressed: handlePressed(context, false, "FilledButton with Icon"),
label: const Text('Icon'),
icon: const Icon(Icons.add),
),
_colDivider,
ElevatedButton.icon(
style: ElevatedButton.styleFrom(
// Foreground color
foregroundColor: Theme.of(context).colorScheme.onSecondaryContainer, backgroundColor: Theme.of(context).colorScheme.secondaryContainer,
).copyWith(elevation: ButtonStyleButton.allOrNull(0.0)),
onPressed:
handlePressed(context, false, "FilledTonalButton with Icon"),
label: const Text('Icon'),
icon: const Icon(Icons.add),
),
_colDivider,
OutlinedButton.icon(
onPressed:
handlePressed(context, false, "OutlinedButton with Icon"),
icon: const Icon(Icons.add),
label: const Text("Icon"),
),
_colDivider,
TextButton.icon(
onPressed: handlePressed(context, false, "TextButton with Icon"),
icon: const Icon(Icons.add),
label: const Text("Icon"),
)
],
),
);
}
}
// This is a stateless widget that displays different variations of floating action buttons
class FloatingActionButtons extends StatelessWidget {
// key constructor parameter
const FloatingActionButtons({super.key});
@override
Widget build(BuildContext context) {
return Padding(
// Adds a padding of 10 pixels vertically to the widget
padding: const EdgeInsets.symmetric(vertical: 10),
child: Wrap(
// Aligns the children evenly along the horizontal axis
alignment: WrapAlignment.spaceEvenly,
// Centers the children along the vertical axis
crossAxisAlignment: WrapCrossAlignment.center,
children: [
// Displays a small floating action button
FloatingActionButton.small(
// Hero tag for animation
heroTag: "btn1",
// Callback function when the button is pressed
onPressed: () {},
// Icon to display inside the button
child: const Icon(Icons.add),
),
_rowDivider,
// Displays a regular floating action button
FloatingActionButton(
// Hero tag for animation
heroTag: "btn2",
// Callback function when the button is pressed
onPressed: () {},
// Icon to display inside the button
child: const Icon(Icons.add),
),
_rowDivider,
// Displays an extended floating action button
FloatingActionButton.extended(
// Hero tag for animation
heroTag: "btn3",
// Callback function when the button is pressed
onPressed: () {},
// Icon to display inside the button
icon: const Icon(Icons.add),
// Text label to display next to the icon
label: const Text("Create"),
),
_rowDivider,
// Displays a large floating action button
FloatingActionButton.large(
// Hero tag for animation
heroTag: "btn4",
// Callback function when the button is pressed
onPressed: () {},
// Icon to display inside the button
child: const Icon(Icons.add),
),
],
),
);
}
}
- The code is a Flutter app that demonstrates various button types in Material Design, including ElevatedButton, FilledButton, FilledTonalButton, OutlinedButton, and TextButton. The app uses Scaffold to create the basic structure of the app and the SingleChildScrollView to create a scrollable area.
- The MaterialButtonRoute class contains the code for the UI of the app, which is defined in the build method. The method creates a column with several rows that contain the different button types.
- For each button type, a corresponding button is created and added to the Column. The buttons have onPressed handlers that call the handlePressed function, which displays a SnackBar with a message indicating which button was pressed. The handlePressed function takes in three parameters: the BuildContext, a boolean flag to indicate if the button is disabled, and the name of the button.
- Each button type has a different appearance and behavior, as defined by the Material Design specification. The buttons are either elevated or filled, and some buttons have a tonal color scheme. Some buttons have an outlined appearance and some buttons have a text-only appearance. The code also demonstrates how to style the buttons, such as changing the foreground and background colors.
- Overall, this code provides a good starting point for using different button types in a Flutter app, and demonstrates how to handle button presses and display messages to the user.
import 'package:flutter/material.dart';
import 'material_buttons.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
useMaterial3: true,
colorSchemeSeed: Colors.pink,
),
home: const MaterialButtonRoute(),
);
}
}
..
..
Comments
Post a Comment