Flutter自定义控件功能扩展插件widget_modifier的使用

Flutter自定义控件功能扩展插件widget_modifier的使用

logo

A collection of built-in flutter widget modifiers, which flatten the widget tree and make it easier to read.

Credit: 原始想法和widget_modifier的基础代码是基于@remi_rousseletnested插件修改而成。


问题

AspectRatio(
  aspectRatio: 16 / 8,
  child: Padding(
    padding: const EdgeInsets.symmetric(horizontal: 20),
    child: DecoratedBox(
      decoration: BoxDecoration(
        color: const Color(0xFFe1e4e3),
        borderRadius: BorderRadius.circular(20),
      ),
      child: Padding(
        padding: const EdgeInsets.all(20),
        child: Row(),
      ),
    ),
  ),
)

这是一个典型的Flutter小部件。由于有四个嵌套的小部件,代码阅读起来非常困难。你需要在PaddingAspectRatioDecoratedBoxPadding之间来回跳转才能看到实际的子小部件。这种过程既不必要又浪费脑力。

当然,在现实世界中没有人会这样做。相反,我们会使用一个友好的家伙——Container。上述小部件可以变为以下形式:

AspectRatio(
  aspectRatio: 16 / 8,
  child: Container(
    margin: const EdgeInsets.symmetric(horizontal: 20),
    decoration: BoxDecoration(
      color: const Color(0xFFe1e4e3),
      borderRadius: BorderRadius.circular(20),
    ),
    padding: const EdgeInsets.all(20),
    child: Row(),
  ),
)

但是,为什么我们仍然需要AspectRatio小部件?因为Container没有aspectRatio字段。这意味着Container无法提供所有你可能需要的配置。

为了解决这个问题,widget_modifier引入了一组新的API来“扁平化”你的小部件。


使用方法

widget_modifier提供了两种API风格:声明式级联式

声明式

声明式的修饰版本的上述示例小部件如下所示:

Modifier(
  modifiers: [
    AspectRatioModifier(
      aspectRatio: 16 / 8,
    ),
    PaddingModifier(
      padding: const EdgeInsets.symmetric(horizontal: 20),
    ),
    DecoratedBoxModifier(
      decoration: BoxDecoration(
        color: const Color(0xFFe1e4e3),
        borderRadius: BorderRadius.circular(20),
      ),
    ),
    PaddingModifier(
      padding: const EdgeInsets.all(20),
    )
  ],
  child: Row(),
),
  • modifiers: 一个List<SingleChildModifier>,基本上是一个典型的具有单个子小部件的小部件包装器。
  • child: Modifier的子小部件。

声明式修饰器会从modifiers列表的底部元素开始应用到顶部元素。

优点与缺点

优点

  • 容易检测根child小部件的位置。
  • 代码格式良好。
  • 与编辑器代码折叠功能配合得很好。

缺点

  • 初学者可能会感到不直观。

级联式

级联式的修饰版本的上述示例小部件如下所示:

Row()
  .modified()
  .wrapWith(PaddingModifier(
    padding: const EdgeInsets.all(20),
  ))
  .wrapWith(DecoratedBoxModifier(
    decoration: BoxDecoration(
      color: const Color(0xFFe1e4e3),
      borderRadius: BorderRadius.circular(20),
    ),
  ))
  .wrapWith(PaddingModifier(
    padding: const EdgeInsets.symmetric(horizontal: 20),
  ))
  .wrapWith(AspectRatioModifier(
    aspectRatio: 16 / 8,
  ))
  • modified(): 扩展方法将你的小部件转换为Modifier
  • wrapWith(): 将SingleChildModifier插入到modifiers列表的开头。
  • wrapWithAll(): 将List<SingleChildModifier>插入到modifiers列表的开头。

级联修饰器会从顶部的wrapWith/wrapWithAll元素开始应用到底部。

优点与缺点

优点

  • 容易检测根child小部件的位置。
  • 阅读起来更直观。

缺点

  • 代码格式有时看起来不够美观。

自定义修饰器

如果你想创建自定义修饰器,可以检查SingleChildStatelessModifierSingleChildStatefulModifier的等效版本,它们分别是StatelessWidgetStatefulWidget

注意事项

⚠️ 你需要覆盖buildWithChild而不是build方法。

⚠️ buildWithChild类似于build,但多了一个child参数,这是Modifier传递给SingleChildModifier的实际小部件。

⚠️ modifierKey是修饰器内部实际小部件的键。


单一状态无状态修饰器

class ConstrainedBoxModifier extends SingleChildStatelessModifier {
  ConstrainedBoxModifier({
    Key? key,
    Widget? child,
    super.modifierKey,
    required this.constraints,
  })  : assert(constraints.debugAssertIsValid()),
        super(key: key, child: child);

  final BoxConstraints constraints;

  [@override](/user/override)
  Widget buildWithChild(BuildContext context, Widget? child) {
    return ConstrainedBox(
      key: modifierKey,
      constraints: constraints,
      child: child,
    );
  }
}

单一状态有状态修饰器

你需要在SingleChildStatefulModifierState类中实现SingleChildStateMixin混入。

class StatefulBuilderModifier extends SingleChildStatefulModifier {
  const StatefulBuilderModifier({
    super.key,
    super.modifierKey,
    required this.builder,
  });

  final SingleChildStatefulWidgetBuilder builder;

  [@override](/user/override)
  State<StatefulWidget> createState() => _StatefulBuilderModifierState();
}

class _StatefulBuilderModifierState extends State<StatefulBuilderModifier>
    with SingleChildStateMixin<StatefulBuilderModifier> {
  [@override](/user/override)
  Widget buildWithChild(BuildContext context, Widget child) {
    return widget.builder(context, setState, child);
  }
}

编辑器支持

你可以轻松地将现有的小部件转换为Modifier。更多信息请查看:


示例代码

以下是完整的示例代码:

// ignore_for_file: unused_import
import 'package:example/benchmark/benchmark_view.dart';
import 'package:example/benchmark/complex_benchmark_view.dart';
import 'package:example/benchmark/modifier_complex_benchmark_view.dart';
import 'package:example/benchmark/modifier_benchmark_view.dart';
import 'package:example/homework_reminder_ui/home_view.dart';
import 'package:example/homework_reminder_ui/modifier_home_view.dart';
import 'package:flex_color_scheme/flex_color_scheme.dart';
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    final theme = FlexColorScheme.light(
      scheme: FlexScheme.amber,
      useMaterial3: true,
    ).toTheme;
    final darkTheme = FlexColorScheme.dark(
      scheme: FlexScheme.amber,
      useMaterial3: true,
    ).toTheme;

    return MaterialApp(
      title: 'Homework tracker',
      theme: theme,
      darkTheme: darkTheme,
      themeMode: ThemeMode.light,
      home: const HomeView(),
      // home: const ModifierHomeView(),
      // home: const ModifierBenchmarkView(),
      // home: const BenchmarkView(),
      // home: const ModifierComplexBenchmarkView(),
      // home: const ComplexBenchmarkView(),
    );
  }
}

更多关于Flutter自定义控件功能扩展插件widget_modifier的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter自定义控件功能扩展插件widget_modifier的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter中,自定义控件和扩展控件的功能是非常常见的需求。widget_modifier 是一个非常有用的插件,它允许你以一种链式的方式修改和扩展现有的Flutter控件。使用 widget_modifier,你可以更容易地为控件添加额外的功能,而不需要创建新的控件类。

安装 widget_modifier 插件

首先,你需要在 pubspec.yaml 文件中添加 widget_modifier 依赖:

dependencies:
  flutter:
    sdk: flutter
  widget_modifier: ^0.0.1 # 请使用最新版本

然后运行 flutter pub get 来安装依赖。

使用 widget_modifier 插件

widget_modifier 提供了 Modifier 类,你可以通过它来链式地修改控件。以下是一个简单的示例,展示了如何使用 widget_modifier 来扩展控件功能。

示例:添加边距和背景颜色

import 'package:flutter/material.dart';
import 'package:widget_modifier/widget_modifier.dart';

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

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Widget Modifier Example')),
        body: Center(
          child: Text('Hello, World!')
              .modifier
              .padding(all: 16.0) // 添加内边距
              .backgroundColor(Colors.blue) // 添加背景颜色
              .cornerRadius(8.0) // 添加圆角
              .build(),
        ),
      ),
    );
  }
}

在上面的示例中,我们使用了 widget_modifier 来为 Text 控件添加内边距、背景颜色和圆角。通过链式调用 modifier 的方法,我们可以轻松地扩展控件的功能。

widget_modifier 提供的一些常用方法

  • padding: 添加内边距
  • margin: 添加外边距
  • backgroundColor: 设置背景颜色
  • cornerRadius: 设置圆角
  • border: 添加边框
  • shadow: 添加阴影
  • onTap: 添加点击事件

自定义 Modifier

你还可以通过继承 Modifier 类来创建自定义的 Modifier。以下是一个自定义 Modifier 的示例:

class CustomModifier extends Modifier {
  final double customValue;

  CustomModifier({required this.customValue});

  [@override](/user/override)
  Widget build(BuildContext context, Widget child) {
    return Container(
      color: Colors.red.withOpacity(customValue),
      child: child,
    );
  }
}

// 使用自定义 Modifier
Text('Hello, World!')
    .modifier
    .custom(CustomModifier(customValue: 0.5))
    .build();
回到顶部