Flutter自定义命令执行插件prop_commands的使用
Flutter自定义命令执行插件prop_commands的使用
该插件包含以下装饰类:Property<T>
、Command
、ParameterizedCommand<T>
、AsyncCommand
、ParameterizedAsyncCommand<T>
。这些类在基于 ChangeNotifier
的视图模型创建时非常有用。
示例 #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

属性和命令在视图模型类 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

在视图模型类 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

在 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操作,创建了三个参数化的异步命令:addCommand
、removeCommand
、updateCommand
。
以 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
更多关于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.kt
和 ios/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)