Flutter可控制组件插件controllable_flutter的使用

controllable_flutter pub version

轻松且方便的状态管理。将您的业务逻辑与UI层分离。

⚠️ 注意:这是一个alpha版本。文档尚未完成,后续会扩展和更新。


快速概览

发送状态更新

@override
void onUpdateName(String newName) {
  emitWith(name: newName);
}

读取状态

Text(context.myController.state.name);

监听状态变化

Text(context.myController.state.watch.name);

触发事件

TextButton(
  onPressed: () => context.myController.raiseEvent.updateName('New name'),
  child: Text('触发更新名称事件'),
);

更多功能

更多详细信息,请参阅下方内容。


目录


示例

设置

pubspec.yaml中添加依赖:

dependencies:
  controllable_flutter:

dev_dependencies:
  build_runner:
  controllable_generator:

首先,声明您的StateEvent类。为了简单起见,我们将使用int作为副作用,但实际上它可以是任何类甚至枚举。

状态

将状态所需的数据字段作为getter声明。这些将在UI和控制器级别上可用。

part of 'home_controller.dart';

abstract class HomeState extends XState {
  String get name;
  String? get address;
}

事件

描述UI可以触发的事件方法。这些将被UI用于触发控制器操作。

part of 'home_controller.dart';

abstract class HomeEvent extends XEvent {
  void updateName(String newName);
  void updateAddress(String newAddress);
  void updateCounter(int counter);
}

声明控制器类

/* 导入 */

part 'home_controller.x.dart';
part 'home_event.dart';
part 'home_state.dart';

@XControllable<HomeEvent>()
class HomeController extends XController<HomeState> with _$HomeController {
  @override
  HomeState createInitialState() {
    // 我们稍后会填充它。
  }
}

运行构建工具

flutter pub run build_runner build

使用

填充控制器

生成了一个包含设置和扩展的文件。现在您可以填写控制器的详细信息:

@XControllable<HomeEvent>()
class HomeController extends XController<HomeState> with _$HomeController {
  @override
  HomeState createInitialState() {
    // 使用以下方法创建控制器的初始状态。
    // 参数与您在HomeState类中声明的相同。
    return createHomeState(name: 'something');
  }

  // 下面的方法称为事件。这些将从UI级别触发。
  // 它们基于HomeEvent类自动生成。
  // 注意,updateName方法变成了onUpdateName等。

  @override
  void onUpdateAddress(String newAddress) {
    // 使用emitWith向UI传递具有更新字段的新状态。
    emitWith(address: newAddress);
  }

  @override
  void onUpdateName(String newName) {
    emitWith(name: newName);
  }

  @override
  void onUpdateCounter(int counter) {
    // 使用fireEffect触发UI层可以捕获的效果
    // 使用XListener小部件。
    // 然后它可以导航到另一个页面,显示一个提示等。
    fireEffect(counter);
  }
}

界面

提供HomeController

return XProvider(
  create: (context) => HomeController(),
  child: const HomeBody(),
);

HomeBody中访问字段:

final controller = context.homeController;

return Column(
  children: [
    Text(controller.state.watch.name),
    Text(controller.state.watch.address),
    TextButton(
      // 调用控制器的onUpdateName方法。
      onPressed: () => controller.raiseEvent.updateName('New Name'),
      child: Text('将名称设置为"New Name"'),
    ),
  ],
);

watch语句将使给定BuildContext的小部件在相应字段更改时重建。因此,在上面的示例中,每当执行emitWith(name: any)emitWith(address: any)时,树都会重新构建。但我们希望避免不必要的重建,对吧?将文本移动到单独的小部件中!或者将其包装在构建器中:

return Column(
  children: [
    Builder(
      // 只有当名称更改时才会重建
      // 因为这个`context`现在只与此部分树相关!
      builder: (context) => Text(context.homeController.state.watch.name)
    ),
    Builder(
      // 只有当地址更改时才会重建
      // 因为这个`context`现在只与此部分树相关!
      builder: (context) => Text(context.homeController.state.watch.address)
    ),
    // 按钮不会在名称或地址未更改时重建
    TextButton(
      onPressed: () => context.homeController.raiseEvent.updateName('New Name'),
      child: Text('将名称设置为"New Name"'),
    ),
  ],
);

如果只想简单地读取字段而不观察它,只需不使用watch访问它:

onPressed: () => print(context.homeController.state.name),

如何操作

发送新状态

在您的控制器中,使用emitWith向UI发送新状态。调用emitWith(yourField: newValue)以更新yourField

监听或读取状态

使用context.controller.state.watch.*监听状态字段的更新。

使用context.controller.state.*简单地读取状态字段。

触发事件

要在UI级别上执行某些业务逻辑,执行context.yourController.raiseEvent.yourEvent。这将在控制器中执行相应的方法。

触发副作用

副作用用于执行UI操作。导航到另一个屏幕、显示对话框或提示、验证表单字段等——这就是副作用的作用。

在您的控制器中,执行:

fireEffect(data);

监听副作用

使用XListener小部件来监听由控制器触发的副作用。

XListener(
  streamable: context.homeController,
  listener: (context, effect) {
    // 在UI级别执行所需的操作。
    print(effect); // 或者只是打印效果...

    // 检查特定类型的副作用,您可以这样做:
    if (effect is MyEffect) {
      // 对MyEffect做些事情
    }
  },
  child: const SomeWidget(),
);
1 回复

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


controllable_flutter 是一个用于在 Flutter 中创建可控制组件的插件。它允许你通过外部控制器来管理组件的状态和行为,从而实现更灵活和可复用的 UI 组件。

安装

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

dependencies:
  flutter:
    sdk: flutter
  controllable_flutter: ^1.0.0  # 请使用最新版本

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

基本用法

controllable_flutter 的核心思想是通过 Controller 来管理组件的状态。你可以通过继承 Controller 类来创建自定义的控制器,并将其与组件绑定。

1. 创建控制器

首先,创建一个控制器类,继承自 Controller

import 'package:controllable_flutter/controllable_flutter.dart';

class MyController extends Controller {
  int _counter = 0;

  int get counter => _counter;

  void increment() {
    _counter++;
    notifyListeners(); // 通知监听器状态已更新
  }
}

2. 创建可控制组件

接下来,创建一个可控制组件,使用 ControllableWidget 来绑定控制器:

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

class MyWidget extends ControllableWidget<MyController> {
  MyWidget({Key? key}) : super(key: key, controller: MyController());

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Controllable Widget Example'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Counter:',
            ),
            Text(
              '${controller.counter}',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: controller.increment,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

3. 使用可控制组件

最后,在你的应用中使用这个可控制组件:

import 'package:flutter/material.dart';
import 'my_widget.dart'; // 导入你创建的可控制组件

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

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Controllable Flutter Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyWidget(), // 使用可控制组件
    );
  }
}

高级用法

1. 多个控制器

你可以为同一个组件绑定多个控制器,以实现更复杂的状态管理。

class MyWidget extends ControllableWidget<MyController> {
  MyWidget({Key? key}) : super(key: key, controller: MyController());

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Controllable Widget Example'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Counter:',
            ),
            Text(
              '${controller.counter}',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: controller.increment,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

2. 监听控制器状态

你可以通过 addListener 方法来监听控制器状态的变化,并在状态变化时执行相应的操作。

class MyWidget extends ControllableWidget<MyController> {
  MyWidget({Key? key}) : super(key: key, controller: MyController());

  [@override](/user/override)
  void initState() {
    super.initState();
    controller.addListener(_onControllerChange);
  }

  void _onControllerChange() {
    // 当控制器状态变化时执行的操作
    print('Counter changed: ${controller.counter}');
  }

  [@override](/user/override)
  void dispose() {
    controller.removeListener(_onControllerChange);
    super.dispose();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Controllable Widget Example'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Counter:',
            ),
            Text(
              '${controller.counter}',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: controller.increment,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}
回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!