What is MaterialStateProperty?

The purpose of MaterialStateProperty is to make it possible to specify different styles for different states.

a button with different styles for different states

For example, if we want a button that’s usually blue, but turns green when it’s pressed, and enlarges its texts at the same time, we can use MaterialStateProperty.resolveWith to do exactly that.

ElevatedButton(
  style: ButtonStyle(
    backgroundColor: MaterialStateProperty.resolveWith((states) {
      // If the button is pressed, return green, otherwise blue
      if (states.contains(MaterialState.pressed)) {
        return Colors.green;
      }
      return Colors.blue;
    }),
    textStyle: MaterialStateProperty.resolveWith((states) {
      // If the button is pressed, return size 40, otherwise 20
      if (states.contains(MaterialState.pressed)) {
        return TextStyle(fontSize: 40);
      }
      return TextStyle(fontSize: 20);
    }),
  ),
  child: Text("Changing Button"),
  onPressed: () {},
)

In addition to checking whether the button is being “pressed”, MaterialStateProperty also supports: disabled, dragged, error, focused, hovered, pressed, scrolledUnder, selected. Note that it’s possible to have multiple states at once. For example, a button can be both “disabled” & “hovered” at the same time. With MaterialStateProperty you can customize its appearance when that happens.

“Okay, but I just want a red button.”

Sure, it seems like you can use: MaterialStateProperty.all(Colors.red) to make it red in all cases. But that’s probably NOT what you want. For example, when the button is disabled, do you still want it to be red?

a red button that's always red, even when disabled

See, “all” means “all”. This is not good.

So what, are we stuck dealing with MaterialStateProperty and checking for disabled states all day?

Thankfully, no. There’s a better way:

If you are using ElevatedButton, you can use ElevatedButton.styleFrom as a base style. Similarly, if you are using TextButton, you can use TextButton.styleFrom. From there, you can easily modify some of the styles.

a red button that can be properly disabled

Code:

ElevatedButton(
  style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
  child: Text("Red Button"),
  onPressed: () {},
)

That’s it, you just pass in a Color class. Super easy, no MaterialStateProperty involved. And it automatically handles edge cases for you.

Leave a Comment