In the world of cross-platform application development, Flutter serves as a powerful tool. One of the fundamental elements contributing to an engaging user interface in Flutter is the use of buttons. Flutter buttons are essential interactive components that trigger an action when users tap or click on them. Decoding the Flutter buttons ecosystem gives us a distinctive perspective on the diverse types of buttons integrated into the Flutter SDK.
In the visual language of a digital interface, buttons act as catalysts of functionality. They carry out specific tasks when users interact with them. For instance, a button could navigate users to the next screen, submit a form, or simply change the colour of a piece of text.
In Flutter, these buttons are brought to life via the button's widget classification. Creating any type of button in Flutter demands a clear understanding of buttons. Think of Flutter buttons as interactive widgets that respond to a series of user events, such as void main being tapped, held (long-pressed), or hovered over.
Flutter buttons have evolved to offer a wealth of options. Initially, Flutter app developers primarily used three types of buttons: FlatButton, RaisedButton, and OutlineButton, and the other supported types like Floating Button, Drop Down Button, Icon Button, Inkwell Button, PopupMenu Button. Each Flutter button served different needs, had different styles, and enhanced various application use cases.
However, to align Flutter more closely with the Material Design specifications and ensure a more flexible, easy-to-configure button experience, Flutter has introduced enhanced versions of these buttons. These advanced versions, namely TextButton (formerly FlatButton), ElevatedButton (formerly RaisedButton), and OutlinedButton (formerly OutlineButton), not only bring an augmented user experience but also offer an easier approach to setting properties and defaults.
The advent of new button widgets in Flutter is not a sudden change but a result of thoughtful progress complementing the dynamic world of UI/UX design. To understand these advancements, let's journey through the evolution of Flutter buttons, from how they were in the beginning, to what they have transformed into now.
The FlatButton, characterized by its lack of background and elevation, was an excellent choice for minimalistic design needs. It was often employed in dialogs, inline with other content, or as a part of a larger component. FlatButton drew special attention as it did not distract from non-interactive yet vital components on the screen.
Here’s an example of using the FlatButton widget.
1 FlatButton( 2 textColor: Colors.blue, 3 onPressed: () { 4 print('FlatButton pressed!'); 5 }, 6 child: Text('FlatButton'), 7 ) 8
The RaisedButton, unlike FlatButton, came with a Material Design elevation effect representing a piece of material paper hovering over the interface. The RaisedButton would raise or elevate when pressed, giving the application a subtle depth and dimension, a pleasant aesthetic experience for users.
An example of RaisedButton is as shown below:
1 RaisedButton( 2 onPressed: () { 3 print('RaisedButton pressed!'); 4 }, 5 child: Text('RaisedButton'), 6 ) 7
The OutlineButton, as its name suggests, was primarily a button outlined by a thin border. This button was a considerable choice when UI required to make less-frequent or less-important actions noticeable but not prevalent.
An example of OutlineButton is as shown below:
1 OutlineButton( 2 onPressed: () { 3 print('OutlineButton pressed!'); 4 }, 5 child: Text('OutlineButton'), 6 ) 7
The FlatButton, RaisedButton, and OutlineButton in Flutter offered a similar set of properties that helped customize their appearance and behaviour. These properties included colors, shape, padding, and dimensions; however, the process could become slightly complex due to the large set of parameters to handle.
Recently, the Flutter team introduced a raft of exciting changes to the Flutter Button API. A primary goal behind these modifications is to align the Flutter framework more closely with Material Design specifications, promoting an intuitive, flexible, and configuration-friendly button setup.
Flutter's relentless pursuit of offering a more streamlined, practical and adaptive ecosystem laid down the roadmap for these recent changes in button classes. Evolving needs for elevated customizability and adaptability were strong influences behind this development. The changes address the hurdles developers faced with the material buttons in terms of themes and constructor parameters, offering a more straightforward approach to properties' assignment, besides opening the door to enhanced UI possibilities.
With the advent of modern, more adaptable button widgets, the original FlatButton, RaisedButton, and OutlineButton widgets of Flutter have been deprecated. Although these classes will continue to function for the time being, they will eventually be phased out. Developers are now encouraged to utilize the updated button classes.
For example, the FlatButton has transformed into the more versatile and stylish TextButton.
In the new TextButton widget, developers will enjoy higher flexibility in controlling the button's characteristics. The new button classes ensure an enjoyable developer experience, which is a priority when creating a user-friendly ecosystem in Flutter.
The upgrading of Flutter's primary button widgets - FlatButton, RaisedButton, and OutlineButton, to TextButton, ElevatedButton, and OutlinedButton, respectively, marks an essential transition towards better design, enhanced usability, and improved functionality.
The TextButton is the updated version of the FlatButton widget in Flutter. The principal characteristics that set it apart include a minimal design that doesn't distract from the overall UI and easy-to-modify visual parameters like color and padding.
1 TextButton( 2 onPressed: () { 3 print('TextButton pressed!'); 4 }, 5 child: Text('TextButton'), 6 ) 7
In this example, we are creating a simple TextButton and printing 'TextButton pressed!' in the console after users press the button.
An ElevatedButton is the upgraded version of RaisedButton. It brings along all the excellencies of the RaisedButton, namely an elevation increase on the press, and adds a host of much-needed widgets and properties around styling and theming.
1 ElevatedButton( 2 onPressed: () { 3 print('ElevatedButton pressed!'); 4 }, 5 child: Text('ElevatedButton'), 6 ) 7
The ElevatedButton in the example above will print 'ElevatedButton pressed!' in the console when pressed.
OutlinedButton refines the OutlineButton's recipe, introducing more flexible styling in terms of color, shape, and size. This button, outlined by default, grants a clear and less-dominating presence on the interface.
1 OutlinedButton( 2 onPressed: () { 3 print('OutlinedButton pressed!'); 4 }, 5 child: Text('OutlinedButton'), 6 ) 7
In the aforementioned snippet, an 'OutlinedButton pressed!' message will reflect in the console as the OutlinedButton is pressed.
The introduction of the newer generation of button widgets in Flutter marks a significant upgrade from the previous generation. Designed to be more versatile, adaptable, and user-friendly, these buttons come with several improvements. Let's take a more in-depth look at each of these.
The TextButton, inheriting the simplicity of FlatButton, is more agile and flexible. This button widget fits perfectly into scenarios that demand minimal user attention, being seamlessly integrated with other components.
The appearance of a TextButton can be customized using ButtonStyle. For example, to modify the foreground (text/icon) color of a TextButton:
1 TextButton( 2 style: ButtonStyle( 3 foregroundColor: MaterialStateProperty.all<Color>(Colors.blue), 4 ), 5 onPressed: () { }, 6 child: Text('TextButton with custom color'), 7 ) 8
In this example, the TextButton's content will be depicted in blue, overriding the default color.
ElevatedButton, an advanced version of RaisedButton, contributes to a complete user experience by adding a material design elevation to the button. This widget adjusts the elevation dynamically based on the state of the button to deliver a profound feedback response to user interactions.
Customizing the ElevatedButton can be done via ButtonStyle, similar to TextButton. Here is an example:
1 ElevatedButton( 2 style: ButtonStyle( 3 backgroundColor: MaterialStateProperty.all<Color>(Colors.green), 4 ), 5 onPressed: () { }, 6 child: Text('ElevatedButton with custom color'), 7 ) 8
The above example demonstrates an ElevatedButton with a green background color.
OutlinedButton embodies the spirit of OutlineButton while extending more styling potentials to developers. OutlinedButton features a thin line (outline) around textual content making itself visually less imposing than other styles. This attribute makes it a preferred choice where less emphasis is desired.
OutlinedButton is also styled with the ButtonStyle object. Hence, let’s delve into an example where we modify the border color of an OutlinedButton:
1 OutlinedButton( 2 style: OutlinedButton.styleFrom( 3 side: BorderSide(color: Colors.red), 4 ), 5 onPressed: () { }, 6 child: Text('OutlinedButton with custom border color'), 7 ) 8
In the code snippet above, we've created an OutlinedButton that showcases a bright red border when rendered on the screen.
The advanced button widgets carry the legacy of the original trio, infused with more flexibilities and configurations.
With the advanced button system in Flutter, the way we style buttons has been revamped as well. Hierarchical, cascading style sheets were regular in the old scheme of things, but now, theming is about configurations and override capabilities. The key player in this new paradigm is the ButtonStyle class.
ButtonStyle, as the name signifies, is a class that holds the descriptions for all visual properties of a button. ButtonStyle does not define the button's properties - it rather provides overrides of the default visual properties for a button. This object is often compared to TextStyle, which follows a very similar principle for text widgets.
Let's take a simple example, where we want to change the foreground color of a TextButton across all states.
1 TextButton( 2 style: ButtonStyle( 3 foregroundColor: MaterialStateProperty.all<Color>(Colors.blue), 4 ), 5 onPressed: () { }, 6 child: Text('TextButton with custom foreground color'), 7 ) 8
In this code snippet, the ButtonStyle is used to set the button's foreground color to blue across all states.
ButtonStyle holds an array of customizable properties to tweak a button's appearance. A few of these properties include backgroundColor, foregroundColor, overlayColor, shadowColor, elevation, padding, minimumSize, and shape to name a few.
To determine the value of these properties, Flutter uses the MaterialStateProperty class that can resolve the property value, based on a button's set of interactive states. These states include pressed, hovered, focused, and disabled. Thus, with ButtonStyle and MaterialStateProperty, styling buttons becomes efficient and intuitive.
MaterialStateProperty is an interface that is designed to resolve a value of a certain type based on the interactive state of a component. To explain how MaterialStateProperty works, let's customize the overlay color of a TextButton.
1 TextButton( 2 style: ButtonStyle( 3 foregroundColor: MaterialStateProperty.all<Color>(Colors.blue), 4 overlayColor: MaterialStateProperty.resolveWith<Color?>( 5 (Set<MaterialState> states) { 6 if (states.contains(MaterialState.hovered)) 7 return Colors.blue.withOpacity(0.04); 8 if (states.contains(MaterialState.focused) || states.contains(MaterialState.pressed)) 9 return Colors.blue.withOpacity(0.12); 10 return null; // Defer to the widget's default. 11 }, 12 ), 13 ), 14 onPressed: () { }, 15 child: Text('TextButton with custom overlay color'), 16 ) 17
In this code snippet, we've customized the overlayColor property of a TextButton using MaterialStateProperty. Based on the button's state, it returns a different value for the overlay color.
With the newer set of buttons, theming becomes way more intuitive and flexible. Flutter introduces dedicated Theme classes for each button, namely TextButtonTheme, ElevatedButtonTheme, and OutlinedButtonTheme. These allow you to specify a ButtonStyle for a set of buttons and create uniformity.
TextButtonTheme is a widget that specifies the ButtonStyle for TextButton widgets within it.
You can specify the default ButtonStyle within the widget tree using TextButtonTheme. Here is an example:
1 MaterialApp( 2 theme: ThemeData.from(colorScheme: ColorScheme.light()).copyWith( 3 textButtonTheme: TextButtonThemeData( 4 style: ButtonStyle( 5 foregroundColor: MaterialStateProperty.all<Color>(Colors.blue), 6 ), 7 ), 8 ), 9 ) 10
The above snippet applies a global theme for TextButtons using TextButtonThemeData.
ElevatedButtonTheme works in a similar way for ElevatedButtons. It specifies a ButtonStyle which is used for all ElevatedButton widgets inside it.
For example, to apply a custom theme to all ElevatedButtons within an app:
1 MaterialApp( 2 theme: ThemeData.from(colorScheme: ColorScheme.light()).copyWith( 3 elevatedButtonTheme: ElevatedButtonThemeData( 4 style: ButtonStyle( 5 backgroundColor: MaterialStateProperty.all<Color>(Colors.green), 6 ), 7 ), 8 ), 9 ) 10
The example above specifies a universal theme for ElevatedButtons using ElevatedButtonThemeData.
In the same manner, OutlinedButtonTheme allows you to specify a ButtonStyle for Outlined Buttons. Here's an example of how to adjust a theme for all OutlinedButtons present in the app:
1 MaterialApp( 2 theme: ThemeData.from(colorScheme: ColorScheme.light()).copyWith( 3 outlinedButtonTheme: OutlinedButtonThemeData( 4 style: ButtonStyle( 5 side: MaterialStateProperty.all<BorderSide>( 6 BorderSide( 7 color: Colors.blue, 8 width: 2, 9 ), 10 ), 11 ), 12 ), 13 ), 14 ) 15
In this code snippet, we are assigning a blue border with a width of 2 to all OutlinedButtons using OutlinedButtonThemeData.
The new themes follow the "normalized" pattern that Flutter adopted for Material widgets. Theme properties and widget constructor parameters are null by default, then non-null theme properties and widget parameters specify an override of the component's default value. Implementing and documenting default values is the responsibility of the button component widgets.
The theme customization available with the latest set of buttons makes it effortless to create a consistent look and feel across all buttons in your app. Remember, the button's style parameter overrides non-null properties specified by the corresponding button theme.
Now that we've familiarized ourselves with Flutter's advanced button widgets and their associated themes, it's time to put theory into practice. Let's look at how we can customize and implement these improved buttons.
Each of the newer button widgets has a unique character in terms of visual appeal and use cases. Understanding how these differences and similarities play out in a coding context will provide better insights into their use.
With TextButton, it's straightforward to accommodate various styles, colors, and layouts. We can fully personalize it according to design requirements. In the example below, we create a TextButton with custom style:
1 TextButton( 2 style: ButtonStyle( 3 foregroundColor: MaterialStateProperty.all<Color>(Colors.purple), 4 backgroundColor: MaterialStateProperty.all<Color>(Colors.yellow), 5 ), 6 onPressed: () { }, 7 child: Text('Custom TextButton'), 8 ) 9
This TextButton appears with a purple text color on a yellow background.
Similarly, in ElevatedButton, developers can bring in their own touch to the widget. Combining it with Material Design elevations can make the interface dynamic and enjoyable. Here's an example of a customized ElevatedButton:
1 ElevatedButton( 2 style: ButtonStyle( 3 backgroundColor: MaterialStateProperty.all<Color>(Colors.blue), 4 elevation: MaterialStateProperty.all<double>(3), 5 ), 6 onPressed: () { }, 7 child: Text('Custom ElevatedButton'), 8 ) 9
The given example shows an ElevatedButton with a blue background and an elevation of 3.
OutlinedButton provides a unique opportunity to create a distinct aesthetic appeal with outlined text content. The customizability allows for a flexible implementation in various UI scenarios. Here's a basic example:
1 OutlinedButton( 2 style: ButtonStyle( 3 side: MaterialStateProperty.all<BorderSide>( 4 BorderSide( 5 color: Colors.red, 6 width: 2, 7 ), 8 ), 9 ), 10 onPressed: () { }, 11 child: Text('Custom OutlinedButton'), 12 ) 13
This OutlinedButton is designed with a thick red border around the button.
Crafting custom buttons with Flutter presents an avenue to explore your creativity. While offering various options for personalization, it ensures that the app's final look aligns with your vision.
With the recent changes in widgets and classes in Flutter, developers may need to update their existing codebase to adapt to these new advancements. Migrating may seem like a daunting task, but Flutter has approached this transition in a way that minimizes the friction.
Here, we'll go through some essential concepts when transitioning from the original buttons to the advanced buttons in Flutter.
For most applications, simply swapping the widget names (FlatButton to TextButton, RaisedButton to ElevatedButton, and OutlineButton to OutlinedButton) should suffice. However, some visual changes might occur due to the updated Material Design specifications. If retaining the look of the original buttons is desired, we can define button styles that match the original visual configurations.
Take this example where we create a TextButton that closely resembles a default FlatButton:
1 final ButtonStyle flatButtonStyle = TextButton.styleFrom( 2 primary: Colors.black87, 3 minimumSize: Size(88, 36), 4 padding: EdgeInsets.symmetric(horizontal: 16.0), 5 shape: const RoundedRectangleBorder( 6 borderRadius: BorderRadius.all(Radius.circular(2)), 7 ), 8 ); 9 10 TextButton( 11 style: flatButtonStyle, 12 onPressed: () { }, 13 child: Text('Looks like a FlatButton'), 14 ) 15
While moving from original buttons to advanced buttons, one frequently encountered case is customizing foreground and background colors. This might involve a minor adjustment to property assignments, but the logic remains the same.
Consider an example where RaisedButton is replaced by ElevatedButton:
1 ElevatedButton( 2 style: ElevatedButton.styleFrom( 3 primary: Colors.red, // background color 4 onPrimary: Colors.white, // foreground color 5 ), 6 onPressed: () { }, 7 child: Text('ElevatedButton with custom foreground/background color'), 8 ) 9
In this code snippet, we create an ElevatedButton with a red background and white foreground color.
Some buttons may have been customized with different focus, hover, or splash colors. Instead of defining individual colors for each state, Flutter now encourages the use of a MaterialStateProperty<Color>
to handle all these states.
Here's how you can migrate this feature:
1 TextButton( 2 style: ButtonStyle( 3 overlayColor: MaterialStateProperty.resolveWith<Color?>( 4 (Set<MaterialState> states) { 5 if (states.contains(MaterialState.focused)) 6 return Colors.red; 7 if (states.contains(MaterialState.hovered)) 8 return Colors.green; 9 if (states.contains(MaterialState.pressed)) 10 return Colors.blue; 11 return null; // Defer to the widget's default. 12 }), 13 ), 14 onPressed: () { }, 15 child: Text('TextButton with custom overlay colors'), 16 ) 17
In the above example, we customize the TextButton's overlay color to change as it focuses, hovers or pressed interactively.
Customizing a button’s disabled state colors is a relatively rare case, but there might be scenarios where you've defined custom colors for disabled foreground or background in FlatButton, RaisedButton, or OutlineButton.
To migrate this customization, you can use the styleFrom method for straightforward color adjustments:
1 ElevatedButton( 2 style: ElevatedButton.styleFrom(onSurface: Colors.red), 3 onPressed: null, 4 child: Text('ElevatedButton with custom disabled colors'), 5 ) 6
This example shows an ElevatedButton whose disabled colors are overridden with the color red.
For complete control over the disabled colors, we must define the style explicitly, in terms of MaterialStateProperties. For instance:
1 ElevatedButton( 2 style: ButtonStyle( 3 backgroundColor: MaterialStateProperty.resolveWith<Color?>( 4 (Set<MaterialState> states) { 5 if (states.contains(MaterialState.disabled)) 6 return Colors.red; 7 return null; // Defer to the widget's default. 8 }), 9 foregroundColor: MaterialStateProperty.resolveWith<Color?>( 10 (Set<MaterialState> states) { 11 if (states.contains(MaterialState.disabled)) 12 return Colors.blue; 13 return null; // Defer to the widget's default. 14 }), 15 ), 16 onPressed: null, 17 child: Text('ElevatedButton with custom disabled colors'), 18 ) 19
In the above code, we've customized an ElevatedButton that turns the background color to red and the foreground color to blue when disabled.
Buttons often have custom shapes and borders to align with the application's overall aesthetics. With the new button classes, there have been changes in how borders and shapes are defined.
Earlier, a button's shape and the appearance of its outline were defined using the same parameter. However, with the recent changes, these properties are specified separately with OutlinedBorder shape and BorderSide side parameters.
Let's look at an example where an OutlinedButton is styled to resemble an OutlineButton with a custom border:
1 final ButtonStyle outlineButtonStyle = OutlinedButton.styleFrom( 2 primary: Colors.black87, 3 minimumSize: Size(88, 36), 4 padding: EdgeInsets.symmetric(horizontal: 16), 5 shape: const RoundedRectangleBorder( 6 borderRadius: BorderRadius.all(Radius.circular(2)), 7 ), 8 ).copyWith( 9 side: MaterialStateProperty.resolveWith<BorderSide>( 10 (Set<MaterialState> states) { 11 if (states.contains(MaterialState.pressed)) 12 return BorderSide( 13 color: Colors.red, 14 width: 1, 15 ); 16 return null; // Defer to the widget's default. 17 }, 18 ), 19 ); 20 21 OutlinedButton( 22 style: outlineButtonStyle, 23 onPressed: () { }, 24 child: Text('Looks like an OutlineButton'), 25 ) 26
As you see in the code snippet above, the OutlinedButton is styled to have a red border when pressed, mimicking the look of an OutlineButton.
The journey of adapting to new technologies can sometimes be challenging, but it's also exciting and rewarding. The evolution of Flutter buttons is no exception. Shifting from FlatButton, RaisedButton, and OutlineButton to TextButton, ElevatedButton, and OutlinedButton, Flutter has made strides towards an improved developer experience and a customizable button ecosystem.
Despite the significant changes that come with the advanced buttons, Flutter has meticulously designed the transition to be as smooth as possible. Existing applications can confidently continue to function with the deprecated buttons until developers decide to move to the newly improved versions.
Abiding by the philosophy of continuous improvement, Flutter unceasingly evolves to adapt to changing developer needs and industry trends. By staying on top of these changes and utilizing the latest features, developers can harness the full capabilities of Flutter.
Every application developed with Flutter hones the essentiality of widgets in creating beautiful, intuitive, and interactive UIs. Joining this convenience bandwagon is WiseGPT, a handy Flutter IDE plugin that's on a mission to render your Flutter development faster, more efficient. By crafting code for your chosen Button widgets directly into your Flutter apps UI files, also aligning with your coding style in the process, WiseGPT eliminates any need for manual development in the entire app development lifecycle.
But, as the saying goes, practice makes perfect. Go ahead, design an app, create intricate Buttons for your apps, and play around with the concepts you've learned today. Make Flutter and WiseGPT your allies, harness the power of widgets and watch as your vision transforms into a tangible, interactive, beautiful Flutter app.
Remember, migrating to the new button widgets is not an urgent requirement but a recommended future step. Embrace the change, play with the new buttons, explore their capabilities, understand their application, and when you feel ready, let them make your app shine.
This brings us to the end of this journey of exploring advanced Flutter buttons. It was an exciting ride, going through the evolution, understanding the changes, and bearing witness to what future Flutter development holds.
Keep exploring, keep coding, and keep creating fantastic apps with Flutter! 💙
Tired of manually designing screens, coding on weekends, and technical debt? Let DhiWise handle it for you!
You can build an e-commerce store, healthcare app, portfolio, blogging website, social media or admin panel right away. Use our library of 40+ pre-built free templates to create your first application using DhiWise.