Flutter自定义UI组件插件pottery的使用

Flutter自定义UI组件插件pottery的使用

本包提供了两个小部件,PotteryLocalPottery,用于根据 Flutter 中的小部件生命周期管理 Pot(单类型依赖注入容器)的生命周期。

为什么这比 Pot 的范围功能更好?

来自 package:potPot 本身具有作用域功能,但它是一个 Dart 包,而不是专门为 Flutter 设计的。

Pottery 是一个弥补这一点的工具。它利用小部件生命周期来限制 Pot 的作用域。在 Flutter 中更自然且更不容易出错。

这将如何使事情变得更好?

虽然你可以从任何地方访问存储在全局变量中的 Pot 非常方便,但这给了你太多自由,让你不知道如何在 Flutter 应用中管理 Pot。例如,你可能会很容易失去对应用代码中特定 Pot 使用位置的跟踪。

Pottery 可以使 Pot 的管理类似于使用 package:provider。参见下文中的示例。

示例

开始使用

pubspec.yaml 文件中添加以下依赖:

dependencies:
  pottery: ^x.x.x

使用

Pottery

首先创建一个作为“挂起”的 Pot,如果在应用启动时还不需要使用它。通常将其分配给一个全局变量。

final counterNotifierPot = Pot.pending<CounterNotifier>(
  disposer: (notifier) => notifier.dispose(),
);

使用 Pottery 并在需要开始使用 Pot 之前指定一个工厂。

Widget build(BuildContext context) {
  // counterNotifierPot 没有工厂。
  // 在此处调用 `counterNotifierPot()` 会抛出 PotNotReadyException 异常。

  ...

  return Scaffold(
    body: Pottery(
      pots: {
        counterNotifierPot: CounterNotifier.new,
      },
      // 在第一次调用此构建器之前,上面的 pots 参数中的新工厂已经准备好。
      builder: (context) {
        // 现在可以使用 counterNotifierPot 的方法和 getter。
        final count = counterNotifierPot();
        ...
      },
    ),
  ),
);

pots 是一个包含 Pot 和工厂键值对的 Map。每个工厂在之后成为相应 Pot 的可用对象。

想象一下 Pottery 类似于 provider 包中的 MultiProvider,尽管它们内部的工作方式非常不同。

  • MultiProvider
    • 创建对象并提供它们,以便它们在树的下方可用。
  • Pottery
    • 替换工厂以使 Pot 在该点之后可用。
    • 小部件树仅用于管理工厂和 Pot 中对象的生命周期,因此 Pot 仍然可以在树外可用。

从树中移除 Pottery(例如,从使用 Pottery 的页面导航回来)会重置 pots 映射中的所有 Pot 并替换它们的工厂,以抛出 PotNotReadyException 异常。

注意:

如果目标 Pot 不是挂起的,并且在其创建时已存在对象,则 Pottery 会立即替换该对象及其工厂。

LocalPottery

此小部件为现有 Pot 定义新的工厂,以创建仅在子树中可用的对象。

重要的是,现有 Pot 的工厂不会被替换,而是为这些 Pot 分配新的单独工厂供本地使用。因此,调用 Pot 仍然会返回全局持有的对象。使用 NearestPotOf.of() 获取本地对象。下面的示例说明了这种行为。

final fooPot = Pot(() => Foo(111));
class ParentWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return LocalPottery(
      pots: {
        fooPot: () => Foo(222),
      },
      builder: (context) {
        print(fooPot()); // 输出 111
        print(fooPot.of(context)); // 输出 222

        return ChildWidget();
      },
    );
  }
}

class ChildWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print(fooPot()); // 输出 111
    print(fooPot.of(context)); // 输出 222
    ...
  }
}

有关更多实际用例,请参阅 main2.dartLocalPottery 文档

请注意,LocalPotteryPottery 之间有几个重要的区别:

  • 对象在 LocalPottery 创建时立即创建,而不是在首次访问 Pot 中的对象时。
  • 如前所述,使用 LocalPottery 创建的对象只能通过 NearestPotOf.of() 访问。
  • 使用 LocalPottery 创建的对象不会在 LocalPottery 从树中移除时自动销毁。使用 disposer 指定清理它们的回调函数。下面是一个示例,其中 disposer 函数清理所有 ChangeNotifier 子类型。
LocalPottery(
  pots: {
    myChangeNotifier: () => MyChangeNotifier(),
    intValueNotifier: () => ValueNotifier(111),
  },
  disposer: (pots) {
    pots.values.whereType<ChangeNotifier>().forEach((v) => v.dispose());
  },
  builder: (context) { ... },
)

注意事项

确保指定返回正确类型的工厂

传递给 pots 的键值对不是类型安全的。

在以下示例中,一个返回 int 值的函数被指定为 String 类型的 Pot 的新工厂。虽然显然是错误的,但静态分析不会告诉你这个错误。错误只会在运行时发生。

final stringPot = Pot.pending<String>();
pots: {
  stringPot: () => 123,
}

更多关于Flutter自定义UI组件插件pottery的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

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


当然,以下是如何在Flutter中使用自定义UI组件插件pottery的一个代码示例。pottery是一个假想的Flutter插件,用于展示自定义UI组件。由于pottery并非一个真实存在的官方或广泛使用的插件,我将模拟一个类似的场景,展示如何集成和使用一个自定义UI组件插件。

假设pottery插件提供了一个自定义的按钮组件CustomButton,我们可以按照以下步骤来使用它。

1. 添加依赖

首先,在你的pubspec.yaml文件中添加pottery插件的依赖(注意:这里pottery是假设的,你需要替换为实际的插件名称和版本)。

dependencies:
  flutter:
    sdk: flutter
  pottery: ^1.0.0  # 假设的版本号

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

2. 导入插件

在你的Dart文件中导入pottery插件。

import 'package:pottery/pottery.dart';

3. 使用自定义组件

现在你可以在你的Flutter应用中使用pottery插件提供的CustomButton组件了。以下是一个简单的示例:

import 'package:flutter/material.dart';
import 'package:pottery/pottery.dart';  // 导入pottery插件

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Pottery Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Pottery Demo'),
      ),
      body: Center(
        child: CustomButton(
          onPressed: () {
            // 按钮点击事件处理
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(content: Text('Custom Button Clicked!')),
            );
          },
          buttonText: 'Click Me',
          buttonColor: Colors.blue,
          textColor: Colors.white,
        ),
      ),
    );
  }
}

4. 假设的CustomButton实现

由于pottery是假设的,这里提供一个可能的CustomButton实现,以便你理解其背后的概念。在实际使用中,你会从插件中获取这个组件的实现。

// 假设这是pottery插件中的CustomButton实现
class CustomButton extends StatelessWidget {
  final VoidCallback onPressed;
  final String buttonText;
  final Color buttonColor;
  final Color textColor;

  const CustomButton({
    Key? key,
    required this.onPressed,
    required this.buttonText,
    this.buttonColor = Colors.blue,
    this.textColor = Colors.white,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      style: ButtonStyle(
        backgroundColor: MaterialStateProperty.all(buttonColor),
        foregroundColor: MaterialStateProperty.all(textColor),
      ),
      onPressed: onPressed,
      child: Text(buttonText),
    );
  }
}

在实际应用中,你会从pottery插件中获取CustomButton的实现,而不是自己定义它。上面的代码只是为了展示如何定义和使用一个类似的自定义按钮组件。

总结

上述步骤展示了如何在Flutter项目中添加和使用一个假设的自定义UI组件插件pottery。你需要将pottery替换为实际的插件名称,并根据插件的文档调整代码。通常,插件的README文件会提供详细的安装和使用指南。

回到顶部