Flutter状态构建插件material_state_builder的使用

Flutter状态构建插件material_state_builder的使用

在构建自定义Widget时,尤其是基于Material Design组件如ElevatedButton时,我们经常需要处理复杂的颜色变化。例如,我们需要为按钮设置不同的背景色和覆盖色,分别表示无操作状态和按下状态的颜色。虽然可以通过设置MaterialStateProperty来解决这个问题,但很难将相同的颜色设置到另一个希望响应相同状态的Widget上。

动机

考虑以下示例,其中有一个包含两个子组件的Row:一个Icon和一个ElevatedButton。在这个例子中,我们为按钮设置了默认状态(蓝色)和按下状态(红色)的颜色。这些颜色分别对应于backgroundColoroverlayColor。然而,我们无法将这些颜色应用到图标上,因为我们无法访问按钮的状态。

Row(
    children: [
        const Icon(Icons.person, color: Colors.blue),
        ElevatedButton(
            style: const ButtonStyle(
                backgroundColor: MaterialStatePropertyAll<Color>(Colors.blue),
                overlayColor: MaterialStatePropertyAll<Color>(Colors.red),
            ),
            onPressed: () {},
            child: const Text('Press me'),
        ),
    ],
)

使用

MaterialStateBuilder插件可以帮助我们轻松地处理这种状态变化。通过MaterialStateBuilder插件,我们可以轻松地将状态控制器传递给需要响应状态变化的Widget。

在以下示例中,我们将之前提到的Row包裹在MaterialStateBuilder中,并使用builder回调返回我们需要响应状态变化的Widget。builder提供了状态控制器和状态集合。我们可以通过将builder提供的状态控制器设置为ElevatedButtonstatesController属性来实现这一点。这样,每当按钮状态发生变化时,builder的主体就会重建。因此,我们可以通过按钮的状态变化来反应图标和按钮本身的变化。

现在我们只需要检查按钮是否被按下,并根据该状态设置相应的颜色;否则,我们设置一个默认颜色。这个颜色变量用于图标和按钮。此外,我们不需要为ElevatedButton指定backgroundColoroverlayColor,而是只需设置backgroundColor,按钮的背景色会随着用户交互而改变。

主要代码

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Material State Builder Example',
      home: Scaffold(
        body: MaterialStateBuilder(
          /// Easy way to set the same color for both the icon and the
          /// button for every button state.
          builder: (controller, states) {
            /// Default color.
            var color = Colors.blue;
            if (states.contains(MaterialState.pressed)) {
              /// Change color when button is pressed.
              color = Colors.red;
            }

            return Row(
              children: [
                Icon(Icons.person, color: color),
                ElevatedButton(
                  statesController: controller,
                  style: ButtonStyle(
                    backgroundColor: MaterialStatePropertyAll<Color>(color),
                  ),
                  onPressed: () {},
                  child: const Text('Press me'),
                ),
              ],
            );
          },
        ),
      ),
    );
  }
}

更多关于Flutter状态构建插件material_state_builder的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter状态构建插件material_state_builder的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,material_state_builder 是 Flutter 中一个用于根据组件状态动态调整其外观的插件。虽然 Flutter 的 Material 库本身提供了许多响应状态的组件,但 material_state_builder 提供了一种更灵活的方式来根据自定义逻辑改变组件的样式。

以下是一个简单的示例,展示了如何使用 material_state_builder 来根据按钮的点击状态改变其颜色:

首先,确保你的 pubspec.yaml 文件中已经包含了必要的依赖项(虽然 material_state_builder 通常不是作为一个独立包使用的,而是 Flutter Material 库的一部分,但这里假设你可能是指自定义状态管理逻辑结合 MaterialStateProperty 的使用)。

dependencies:
  flutter:
    sdk: flutter

然后,在你的 Dart 文件中,你可以这样实现:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('MaterialStateBuilder Demo'),
        ),
        body: Center(
          child: MyStatefulButton(),
        ),
      ),
    );
  }
}

class MyStatefulButton extends StatefulWidget {
  @override
  _MyStatefulButtonState createState() => _MyStatefulButtonState();
}

class _MyStatefulButtonState extends State<MyStatefulButton> {
  bool isPressed = false;

  void handlePress() {
    setState(() {
      isPressed = !isPressed;
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialStateBuilder(
      states: [
        if (isPressed) MaterialState.pressed,
        MaterialState.hovering,
        MaterialState.focused,
      ],
      child: ElevatedButton(
        onPressed: handlePress,
        style: ButtonStyle(
          overlayColor: MaterialStateProperty.resolveWith<Color?>(
            (Set<MaterialState> states) {
              if (states.contains(MaterialState.pressed)) {
                return Colors.red;
              }
              if (states.contains(MaterialState.hovering)) {
                return Colors.blue.withOpacity(0.5);
              }
              if (states.contains(MaterialState.focused)) {
                return Colors.green.withOpacity(0.5);
              }
              return null; // Default to button's theme color
            },
          ),
        ),
        child: Text('Press Me'),
      ),
    );
  }
}

在这个示例中:

  1. MyStatefulButton 是一个有状态的组件,它包含一个布尔值 isPressed 来跟踪按钮是否被按下。
  2. MaterialStateBuilder 被用来根据按钮的不同状态(按下、悬停、聚焦)应用不同的样式。
  3. ButtonStyleMaterialStateProperty.resolveWith 被用来根据当前状态动态解析样式。如果按钮被按下,它将显示红色;如果鼠标悬停在按钮上,它将显示半透明的蓝色;如果按钮获得焦点,它将显示半透明的绿色。

这种方式使得你可以非常灵活地根据组件的不同状态应用不同的样式,而不需要为每个状态创建单独的组件。

回到顶部