Flutter Component Collection | A new generation of Button buttons

theme: cyanosis

Continue to create, accelerate growth! This is the second day of my participation in the "Nuggets Daily New Project · October Update Challenge", Click to view event details

0. Status of the button family

With the release of Flutter 3.3, the RaisedButton component was removed from the Flutter framework, and the three button brothers who pioneered the interface are completely a thing of the past.

In addition, MaterialButton and RawMaterialButton will also be abandoned in the future, so it is not recommended that you use them again:

At present, there are three button components, TextButton, ElevatedButton, and OutlinedButton. This article will focus on how to use these three.

In addition, some simple button wrapper components can still be used:

CupertinoButton :  iOS style button
CupertinoNavigationBarBackButton :  iOS Navigation bar back button
BackButton :  back button
IconButton :  icon button
CloseButton :  close button
FloatingActionButton :  floating button
copy

There are also some multi-button integrated components, which will be described in detail in subsequent articles:

CupertinoSegmentedControl
CupertinoSlidingSegmentedControl
ButtonBar
DropdownButton
ToggleButtons
copy
1. The default behavior of the three button components

The following is the default behavior of ElevatedButton: rounded corners and shadows, and water ripples when clicked. When constructing, you must pass in the click callback function onPressed and the child component child :

ElevatedButton(
  onPressed: () {},
  child: Text('ElevatedButton'),
),
copy

The following is the default behavior of OutlinedButton: rounded corners and outer edges, no padding inside, and water ripples when clicked. When constructing, you must pass in the click callback function onPressed and the child component child :

OutlinedButton(
  onPressed: () {},
  child: Text('OutlinedButton'),
);
copy

The following is the default behavior of TextButton: no border, no padding, and water ripples when clicked. When constructing, you must pass in the click callback function onPressed and the child component child :

TextButton(
  onPressed: () {},
  child: Text('TextButton'),
);
copy
2. Button style change

If you look at the source code a little, you can see that these three buttons are essentially the same, and they are all derived classes of ButtonStyleButton. It's just that their default style ButtonStyle is different:

As shown below, queue two abstract methods in the ButtonStyleButton class, which need to be implemented by subclasses, returning the default button style:

Take the ElevatedButton component below, which needs to implement the defaultStyleOf method to return the default theme. When Material3 is not used, related properties are set according to the theme through the styleFrom static method: such as various colors, shadows, text styles, margins, shapes, etc.

Therefore, to modify the button style, you only need to provide the style property setting: the property type is ButtonStyle, and the three button components provide the styleFrom static method to create the ButtonStyle object, which is used as follows:

ButtonStyle style = ElevatedButton.styleFrom(
  backgroundColor: Colors.orange,
  foregroundColor: Colors.white,
  elevation: 0,
  padding: const EdgeInsets.symmetric(horizontal: 40),
  shape: const StadiumBorder(),
  side: const BorderSide(color: Colors.black,),
);

ElevatedButton(
   onPressed: () {},
   child: Text('Login'),
   style: style
);
copy

You can shape by specifying shape, as shown below, and implement a circle component through CircleBorder:

ButtonStyle style = ElevatedButton.styleFrom(
  backgroundColor: Colors.blue,
  foregroundColor: Colors.white,
  elevation: 2,
  shape: const CircleBorder(),
);

ElevatedButton(
    onPressed: () {},
    style: style,
    child: const Icon(Icons.add)
);
copy

The three buttons, TextButton, ElevatedButton, and OutlinedButton, have different default themes. If you provide the same configuration, OutlinedButton can achieve the following display effect.

ButtonStyle style = OutlinedButton.styleFrom(
  backgroundColor: Colors.blue,
  foregroundColor: Colors.white,
  elevation: 0,
  shape: const CircleBorder(),
  side:BorderSide.none
);

OutlinedButton(
    onPressed: () {},
    style: style,
    child: const Icon(Icons.add)
);
copy

Common style properties:

property name

type

use

foregroundColor

Color?

foreground color

backgroundColor

Color?

background color

disabledForegroundColor

Color?

Foreground color when disabled

disabledBackgroundColor

Color?

background color when disabled

shadowColor

Color?

shadow color

elevation

double?

shadow depth

textStyle

TextStyle?

text style

padding

EdgeInsetsGeometry?

margin

side

BorderSide?

sideline

shape

OutlinedBorder?

shape

In addition, there are some less commonly used properties, just take a look at them:

property name

type

use

alignment

AlignmentGeometry?

Alignment in subcomponent area

enableFeedback

bool?

Whether to enable feedback, such as long-press vibration

enabledMouseCursor

MouseCursor?

Desktop mouse style

disabledMouseCursor

MouseCursor?

Desktop mouse style when disabled

animationDuration

Duration?

animation duration

minimumSize

Size?

smallest size

maximumSize

Size?

biggest size

fixedSize

Size?

Fixed size

padding

EdgeInsetsGeometry?

margin

3. Button events

All three buttons need to pass in the onPressed parameter as the click callback when they are constructed. In addition, there are three callbacks onLongPress for listening for long press events; onHover for listening for mouse hover events; onFocusChange for listening for focus change events.

ElevatedButton(
  onPressed: () {
    print('========Login==========');
  },
  onHover: (bool value) {
    print('=====onHover===$value==========');
  },
  onLongPress: () {
    print('========onLongPress==========');
  },
  onFocusChange: (bool focus) {
    print('=====onFocusChange===$focus==========');
  },
  child: const Text('Login'),
);
copy

When the button's onPressed and onLongPress are both null , the button will be disabled . At this time, the button will not respond to clicks, and there is no water ripple effect; in addition, the background color and foreground color of the button are respectively disabledBackgroundColor and disabledForegroundColor Attributes:

ElevatedButton(
  onPressed: null,
  style: style,
  child: const Text('Login'),
);
copy
4. Button size

In the default button style, the minimum size is specified as Size(64, 36) and the maximum size is unlimited.

That is, within the allowable range of the parent's area constraints, the button's size is determined by the child component and the margin. As shown below, the text in the subcomponent is very large, and the button size will be adapted to the size of the text.

ButtonStyle style = ElevatedButton.styleFrom(
  // slightly...
  padding: const EdgeInsets.symmetric(horizontal: 40,vertical: 10),
);

ElevatedButton(
    onPressed: null,
    style: style,
    child: const Text('Login',style: TextStyle(fontSize: 50),),
);
copy

The parent constraint must not be violated, and under tight constraints, the size of the button will be locked. As follows, apply a tight constraint of 200*40 to the button through SizedBox:

SizedBox(
  width: 200,
  height: 40,
  child: ElevatedButton(
    onPressed: (){},
    style: style,
    child: const Text('Login'),
  ),
);
copy

As follows, the tight constraint width is set to 10, you can see that the button can only follow. Even if its minimum size is Size(64, 36), it cannot violate the parent's constraints:

Therefore, if you want to modify the size of the button, there are two ways:

  1. Start with the child component size margins and adjust the button size.
  2. Apply a tight constraint to the button, locking the button size.
5. A brief look at the source code implementation of the ButtonStyleButton component

First of all, ButtonStyleButton is an abstract class that inherits from StatefulWidget, indicating that it needs to rely on the state class to implement internal changes.

Return the _ButtonStyleState state object in the createState method, indicating that the logic of button construction is in this state class:

@override
State<ButtonStyleButton> createState() => _ButtonStyleState();
copy

Looking directly at the constructor in _ButtonStyleState, it will trigger the component's themeStyleOf and defaultStyleOf abstract methods to get the ButtonStyle object at first. This is the logic that TextButton, ElevatedButton, and OutlinedButton need to complete as implementation classes.

The constructed component is the final representation of the button, which uses the ConstrainedBox component to handle constraints; the Material component to handle basic presentation content; InkWell to handle water ripples and related events; Padding to handle padding; and Align to handle alignment.

Use, in general: The ButtonStyleButton component is just a combination of some common components, and the style configuration is performed through the ButtonStyle class to simplify the construction logic. Simplified use through packaging. In addition, we can unify the styles through themes without configuring them one by one, which will be introduced later. That's it for this article, thank you for watching~

Tags: Linux

Posted by PHPist on Wed, 05 Oct 2022 16:37:55 +1030