Skip to content

Instantly share code, notes, and snippets.

@craiglabenz
Last active March 23, 2022 19:54
Show Gist options
  • Save craiglabenz/cec99089cdba23c8b8f31fd9005fb821 to your computer and use it in GitHub Desktop.
Save craiglabenz/cec99089cdba23c8b8f31fd9005fb821 to your computer and use it in GitHub Desktop.
Demonstrates use of MaterialStateProperty API
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
// If an attribute is of type MaterialStateColor, you can supply either
// a regular color, or a MaterialStateProperty-style resolver.
// backgroundColor: Colors.blueAccent,
backgroundColor: MaterialStateColor.resolveWith((states) => Colors.blueAccent),
title: const Text('Material State Properties', style: TextStyle(color: Colors.white)),
),
body: const Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends StatefulWidget {
const MyWidget({Key? key}) : super(key: key);
@override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
// Create a few FocusNodes to simulate tab-traversal, which is a bit
// finicky in DartPad.
FocusNode focusNodeOne = FocusNode();
FocusNode focusNodeTwo = FocusNode();
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
TextButton(
// Clicking a button simulates tab-traversing to that button.
onPressed: () => focusNodeOne.requestFocus(),
focusNode: focusNodeOne,
// Delegate color selection to a MaterialStateProperty
style: const ButtonStyle(
backgroundColor: ButtonBackgroundColor(Colors.pink)),
child:
const Text('A Button', style: TextStyle(color: Colors.white)),
),
ElevatedButton(
// Clicking a button simulates tab-traversing to that button.
onPressed: () => focusNodeTwo.requestFocus(),
focusNode: focusNodeTwo,
// Delegate color selection to a MaterialStateProperty
style: const ButtonStyle(
backgroundColor: ButtonBackgroundColor(Colors.blue)),
child: const Text('Another Button',
style: TextStyle(color: Colors.white)),
),
OutlinedButton(
onPressed: () {},
style: OutlinedButton.styleFrom(
primary: Colors.orange,
),
child: const Text('Custom styled button'),
),
],
),
);
}
}
/// Helper which creates a contained `MaterialStateProperty<Color?>` resolver.
///
/// Credit to Nash (https://twitter.com/Nash0x7E2) for highlighting this
/// opportunity in his I/O Extended Montreal talk at:
/// https://www.youtube.com/watch?v=CrO7_qrL_f0
class ButtonBackgroundColor implements MaterialStateProperty<Color?> {
const ButtonBackgroundColor(this.baseColor);
final Color baseColor;
@override
Color? resolve(Set<MaterialState> states) {
Color? color = states.isFocused ? Colors.orange : baseColor;
Color? darkerVersion = Color.lerp(color, Colors.black, 0.7);
// Darken our button color for each state we want to reflect. Buttons will
// incrementally darken as more states are applied.
if (states.isHovered) {
color = Color.lerp(color, darkerVersion, 0.3);
}
if (states.isPressed) {
color = Color.lerp(color, darkerVersion, 0.3);
}
return color;
}
}
extension MaterialStateSet on Set<MaterialState> {
bool get isHovered => contains(MaterialState.hovered);
bool get isFocused => contains(MaterialState.focused);
bool get isPressed => contains(MaterialState.pressed);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment