Flutter自定义命令执行插件prop_commands的使用

Flutter自定义命令执行插件prop_commands的使用

该插件包含以下装饰类:Property<T>CommandParameterizedCommand<T>AsyncCommandParameterizedAsyncCommand<T>。这些类在基于 ChangeNotifier 的视图模型创建时非常有用。

示例 #1

示例 #1 的工作情况

属性和命令在视图模型类 FirstPageNotifier 中定义。

属性

用于存储计数器值

late final outputProperty = Property<int>(
    initialValue: 0,
    notifyListeners: notifyListeners,
);

属性的初始值设置,并且当此属性的值发生变化时调用 notifyListeners() 方法。

FirstPage 类的 build(BuildContext context) 方法中,我们获取对属性值的跟踪引用

final output =
    FirstPageInheritedNotifier.watchNotifier(context).outputProperty.value;

输出值的方式如下

Text(
    output.toString(),
    style: Theme.of(context).textTheme.headlineLarge,
),

命令

为计数器的递增和递减创建了两个命令

late final incrementCommand = Command(
    action: () => outputProperty.value += 1,
    canAction: () => outputProperty.value < 3,
);

late final decrementCommand = Command(
    action: () => outputProperty.value -= 1,
    canAction: () => outputProperty.value > 0,
);

传递更改计数器属性值的方法作为 action 参数的参数。传递限制计数器值范围的方法作为 canAction 参数的参数,这限制了命令的可用性。

FirstPage 类的 build(BuildContext context) 方法中获取到命令的引用

final incrementCommand =
    FirstPageInheritedNotifier.readNotifier(context).incrementCommand;
final decrementCommand =
    FirstPageInheritedNotifier.readNotifier(context).decrementCommand;

使用命令来操作按钮

ElevatedButton(
    onPressed: decrementCommand.canExecute()
        ? decrementCommand.execute
        : null,
    child: const Icon(Icons.exposure_minus_1),
),

ElevatedButton(
    onPressed: incrementCommand.canExecute()
        ? incrementCommand.execute
        : null,
    child: const Icon(Icons.plus_one),
),

可以看到,在 onPressed 方法中检查了命令的可执行性,这影响了按钮的点击可用性。

示例 #2

示例 #2 的工作情况

属性和命令在视图模型类 SecondPageNotifier 中定义。

属性

定义一个属性以显示计数器值,该属性仅通过其初始值设置。

final outputProperty = Property<int>(initialValue: 0);

SecondPage 类的 build(BuildContext context) 方法中获取对属性值的跟踪引用

final output =
    SecondPageInheritedNotifier.watchNotifier(context).outputProperty.value;

显示属性值的方式如下

Text(
    output.toString(),
    style: Theme.of(context).textTheme.headlineLarge,
),

命令

定义了一个通用的参数化命令,用于按钮, 当调用执行时,将接受一个 int 值作为参数。

late final changeCommand = ParameterizedCommand<int>(
    action: (value) => outputProperty.value += value,
    notifyListeners: notifyListeners,
);

在执行命令方法时,调用 notifyListeners()

SecondPage 类的 build(BuildContext context) 方法中我们获取到命令的引用

final command =
        SecondPageInheritedNotifier.readNotifier(context).changeCommand;

使用命令的方式如下

ElevatedButton(
    onPressed: () => command(-1),
    child: Text(
        '-1',
        style: Theme.of(context).textTheme.titleLarge,
    ),
),

...

ElevatedButton(
    onPressed: () => command(3),
    child: Text(
        '3',
        style: Theme.of(context).textTheme.titleLarge,
    ),
),

示例 #3

示例 #3 的工作情况

在视图模型类 ThirdPageNotifier 中定义了三个属性和一个命令。

属性

设置了带有 notifyListeners() 调用的 CheckboxListTile 属性。

late final isEnabledProperty = Property<bool>(
    initialValue: false,
    notifyListeners: notifyListeners,
);

接下来,在 _ThirdPageState 中获取到这个属性的跟踪引用

final isEnabledProperty =
    ThirdPageInheritedNotifier.watchNotifier(context).isEnabledProperty;

并这样使用它

CheckboxListTile(
    title: const Text('启用输入行'),
    controlAffinity: ListTileControlAffinity.platform,
    contentPadding: const EdgeInsets.all(50),
    value: isEnabledProperty.value,
    onChanged: (value) {
        isEnabledProperty.value = value!;
    },
),

设置了带有 notifyListeners() 调用和验证规则的 TextField 属性。

late final inputProperty = Property<String>(
    initialValue: '',
    notifyListeners: notifyListeners,
    verificationRules: <String, bool Function(String)>{
      '值不能为空字符串': (value) => value.isEmpty,
      '字符串长度不能少于3个字符': (value) => value.length < 3,
    },
);

对于验证规则,指定用户文本消息作为键,返回 true 的方法作为值。

InputTextWidget 中获取到属性的引用

final isEnabledProperty =
        ThirdPageInheritedNotifier.watchNotifier(context).isEnabledProperty;
final inputProperty =
    ThirdPageInheritedNotifier.readNotifier(context).inputProperty;

并这样使用它

TextField(
    decoration: InputDecoration(
        border: const OutlineInputBorder(),
        labelText: '输入值',
        errorText: inputProperty.hasErrors ? inputProperty.errors[0] : null,
    ),
    enabled: isEnabledProperty.value,
    controller: controller,
    onChanged: (text) {
        inputProperty.value = text;
    },
),

在这一行 errorText: inputProperty.hasErrors ? inputProperty.errors[0] : null, 定义了当输入数据时向用户显示错误消息的逻辑。

通过 isEnabledProperty 属性将 TextField 的输入可用性与 CheckboxListTile 的值绑定在一起

enabled: isEnabledProperty.value,

inputProperty 属性在 onChanged 方法中定义的更新其值。

简单的属性用于输出结果

final outputProperty = Property<String>(initialValue: '');

命令

该示例使用了一个异步命令

late final submitCommand = AsyncCommand(
    action: () async {
      await Future.delayed(const Duration(milliseconds: 100));
      outputProperty.value = inputProperty.value;
      inputProperty.value = '';
      isEnabledProperty.value = false;
    },
    canAction: () => inputProperty.hasErrors == false,
    notifyListeners: notifyListeners,
);

按钮的可用性取决于输入时是否存在错误

canAction: () => inputProperty.hasErrors == false,

在执行命令方法时,调用 notifyListeners()

_ThirdPageState 中获取到命令的引用

final submitCommand =
    ThirdPageInheritedNotifier.readNotifier(context).submitCommand;

并这样使用命令

ElevatedButton(
    onPressed: submitCommand.canExecute()
        ? (() async {
            await submitCommand.execute();
            controller.clear();
        })
        : null,
    child: const Icon(Icons.done),
),

示例 #4

示例 #4 的工作情况

FourthPageNotifier 视图模型类中定义了一个属性和三个命令。

属性

创建了一个属性以显示列表。

final peopleProperty = Property<List<Person>>(
    initialValue: [],
);

PeopleListViewWidget 中获取到属性的跟踪引用

final people =
    FourthPageInheritedNotifier.watchNotifier(context).peopleProperty.value;

使用 ListView.builder()ListTile 显示人员集合

ListView.builder(
    itemCount: people.length,
    itemBuilder: (context, index) {
        final person = people[index];
        return ListTile(
            onTap: () async {...},
            title: Text(person.fullName),
            subtitle: Text('ID: ${person.id}'),
            trailing: TextButton(...),
        );
    },
),

命令

为了实现对人员集合的CRUD操作,创建了三个参数化的异步命令:addCommandremoveCommandupdateCommand

addCommand 为例。

late final addCommand = ParameterizedAsyncCommand<List<String>>(
    action: (value) async {
      await _db.create(names: value);
      peopleProperty.value = await _db.getPeople();
    },
    notifyListeners: notifyListeners,
);

Composerwidget 中的 Widget build(BuildContext context) 方法中获取到命令的引用

final command =
    FourthPageInheritedNotifier.readNotifier(context).addCommand;

我们这样使用命令

TextButton(
    onPressed: () async {
        final names = [
            firstNameController.text,
            lastNameController.text,
        ];
        await command(names);
        firstNameController.clear();
        lastNameController.clear();
    },
    child: Text(
    '添加到列表',
    style: Theme.of(context).textTheme.titleMedium,
))

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

1 回复

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


在 Flutter 中,你可以通过创建自定义插件来执行特定的命令或功能。prop_commands 并不是 Flutter 官方提供的插件,因此它可能是某个开发者或团队创建的自定义插件。为了帮助你理解如何使用自定义命令执行插件,我将提供一个通用的步骤和示例,假设你有一个名为 prop_commands 的插件。

1. 添加插件依赖

首先,你需要在 pubspec.yaml 文件中添加插件的依赖。假设 prop_commands 已经发布在 pub.dev 上,你可以这样添加依赖:

dependencies:
  flutter:
    sdk: flutter
  prop_commands: ^1.0.0  # 假设插件的版本是 1.0.0

然后运行 flutter pub get 来获取依赖。

2. 导入插件

在你的 Dart 文件中导入插件:

import 'package:prop_commands/prop_commands.dart';

3. 使用插件执行命令

假设 prop_commands 插件提供了一个 executeCommand 方法来执行命令,你可以这样使用它:

void executeCustomCommand() async {
  try {
    String result = await PropCommands.executeCommand('your_command_here');
    print('Command executed successfully: $result');
  } catch (e) {
    print('Failed to execute command: $e');
  }
}

4. 处理命令结果

executeCommand 方法可能会返回一个 String 或其他类型的结果,你可以根据需要进行处理。例如,将结果显示在 UI 上:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Prop Commands Example'),
        ),
        body: Center(
          child: ElevatedButton(
            onPressed: () async {
              String result = await PropCommands.executeCommand('your_command_here');
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(content: Text('Result: $result')),
              );
            },
            child: Text('Execute Command'),
          ),
        ),
      ),
    );
  }
}

5. 处理错误

在执行命令时,可能会遇到错误。你可以使用 try-catch 块来捕获并处理这些错误。

6. 自定义插件的实现

如果你需要自己实现一个类似的插件,你可以使用 Flutter 的 MethodChannel 来与平台(Android/iOS)进行通信。以下是一个简单的示例:

Dart 部分 (lib/prop_commands.dart):

import 'package:flutter/services.dart';

class PropCommands {
  static const MethodChannel _channel = MethodChannel('prop_commands');

  static Future<String> executeCommand(String command) async {
    try {
      final String result = await _channel.invokeMethod('executeCommand', {'command': command});
      return result;
    } on PlatformException catch (e) {
      throw 'Failed to execute command: ${e.message}';
    }
  }
}

Android 部分 (android/src/main/kotlin/com/example/prop_commands/PropCommandsPlugin.kt):

package com.example.prop_commands

import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.plugin.common.PluginRegistry.Registrar

class PropCommandsPlugin: MethodCallHandler {
  companion object {
    @JvmStatic
    fun registerWith(registrar: Registrar) {
      val channel = MethodChannel(registrar.messenger(), "prop_commands")
      channel.setMethodCallHandler(PropCommandsPlugin())
    }
  }

  override fun onMethodCall(call: MethodCall, result: Result) {
    when (call.method) {
      "executeCommand" -> {
        val command = call.argument<String>("command")
        // 执行命令并返回结果
        result.success("Executed: $command")
      }
      else -> result.notImplemented()
    }
  }
}

iOS 部分 (ios/Classes/PropCommandsPlugin.m):

#import "PropCommandsPlugin.h"

[@implementation](/user/implementation) PropCommandsPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
  FlutterMethodChannel* channel = [FlutterMethodChannel
      methodChannelWithName:@"prop_commands"
            binaryMessenger:[registrar messenger]];
  PropCommandsPlugin* instance = [[PropCommandsPlugin alloc] init];
  [registrar addMethodCallDelegate:instance channel:channel];
}

- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
  if ([@"executeCommand" isEqualToString:call.method]) {
    NSString *command = call.arguments[@"command"];
    // 执行命令并返回结果
    result([NSString stringWithFormat:@"Executed: %@", command]);
  } else {
    result(FlutterMethodNotImplemented);
  }
}
[@end](/user/end)

7. 注册插件

android/app/src/main/kotlin/com/example/your_app/MainActivity.ktios/Runner/AppDelegate.swift 中注册插件。

Android:

import com.example.prop_commands.PropCommandsPlugin

class MainActivity: FlutterActivity() {
  override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
    super.configureFlutterEngine(flutterEngine)
    PropCommandsPlugin.registerWith(registrarFor("com.example.prop_commands.PropCommandsPlugin"))
  }
}

iOS:

#import "GeneratedPluginRegistrant.h"
#import "PropCommandsPlugin.h"

[@implementation](/user/implementation) AppDelegate
- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [GeneratedPluginRegistrant registerWithRegistry:self];
  [PropCommandsPlugin registerWithRegistrar:[self registrarForPlugin:@"PropCommandsPlugin"]];
  return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
[@end](/user/end)
回到顶部