Flutter撤销操作插件nf_flutter_undo的使用
Flutter撤销操作插件nf_flutter_undo的使用
Flutter插件nf_flutter_undo
提供了基于.NET项目中常见的命令模式的简单撤销/重做系统。
使用
首先,在你的Widget树中添加一个InheritedUndo
:
/// 省略 ...
InheritedUndo(
child: Placeholder(),
)
然后创建一个命令,并实现execute
和unexecute
函数:
BasicCommand bc = BasicCommand(
commandName: "<Command Name>",
execute: () {
setState(() => values.add(c));
},
canExecute: () => true,
canUnexecute: () => values.isNotEmpty,
unexecute: () {
setState(() => values.removeLast());
},
);
接着将该命令添加到撤销堆栈并执行它:
InheritedUndo.of(context).undoStack.pushCommand(bc);
bc.execute();
这会将命令推送到UndoStack
,现在它可以被弹出和推送。
UndoStack接口
UndoStack
具有以下接口:
class UndoStack {
/// 最大允许在历史堆栈中的元素数量
///
/// 必须是一个正整数
///
/// 较大的值意味着程序会直接消耗更多的内存来存储更多的撤销状态
final int maxStackSize;
/// 指向用户已经撤销到的位置
///
/// 该指针用于启用重做功能
///
/// 一个命令可以被“撤销”,此时堆栈指针增加1
/// 命令的“unexecute()”函数会被运行,但不会从堆栈中实际移除
///
/// 如果用户“重做”该命令,堆栈指针减少1
/// 命令的“execute()”函数会被运行,但不会将任何东西推入堆栈
///
/// 如果用户“撤销”了一个命令,然后添加了一个新命令,堆栈指针被设置为‘0’,重做不再可能
int stackPointer = -1;
/// 当前堆栈中可撤销元素的数量
int get stackSize;
bool get canUndo;
bool get canRedo;
/// 将此命令添加到堆栈。执行时间在命令内部记录。
///
/// 添加到堆栈并不意味着执行——你需要自行调用`execute()`,可以在添加到堆栈之前或之后执行
void pushCommand(ICommand command);
/// 撤销最近的一个可撤销命令
///
/// 如果命令无法撤销,则从列表中删除该命令,并继续搜索直到:
/// * 列表为空
/// * 找到一个可撤销的元素
///
/// 返回被撤销的`CommandHistory`对象,如果没有撤销则返回`null`
CommandHistory? undo();
/// 重做堆栈头部的命令
CommandHistory? redo();
/// 返回最近应用的命令
///
/// 注意:不要执行或取消执行由该方法返回的命令,否则撤销堆栈将失去状态一致性
CommandHistory? peekCurrent();
/// 返回最近撤销的命令
///
/// 注意:不要执行或取消执行由该方法返回的命令,否则撤销堆栈将失去状态一致性
CommandHistory? peekForward();
/// 返回当前命令堆栈的不可修改列表视图
List<CommandHistory> listCommands();
/// 清空当前历史记录。此操作不可撤销。
void clearHistory();
}
示例Demo
下面是一个完整的示例,展示了如何使用nf_flutter_undo
插件实现撤销和重做功能:
import 'package:flutter/material.dart';
import 'package:nf_flutter_undo/src/command/basic_command.dart';
import 'package:nf_flutter_undo/src/undo/inherited_undo.dart';
class UndoView extends StatefulWidget {
const UndoView({super.key});
static const String routeName = "UndoTest";
[@override](/user/override)
State<UndoView> createState() => _UndoViewState();
}
class _UndoViewState extends State<UndoView> {
List<String> values = [];
int pc = 0;
[@override](/user/override)
void initState() {
super.initState();
}
void undo() {
InheritedUndo.of(context).undoStack.undo();
}
void redo() {
InheritedUndo.of(context).undoStack.redo();
}
void reset() {
InheritedUndo.of(context).undoStack.clearHistory();
setState(() => values.clear());
}
void add() {
const String chars = "abcdefghijklmnopqrstuvwxyz";
String c = chars[pc % chars.length];
pc += 1;
BasicCommand bc = BasicCommand(
commandName: "Add '$c'",
execute: () {
setState(() => values.add(c));
},
canExecute: () => true,
canUnexecute: () => values.isNotEmpty,
unexecute: () {
setState(() => values.removeLast());
},
);
InheritedUndo.of(context).undoStack.pushCommand(bc);
bc.execute();
}
[@override](/user/override)
Widget build(BuildContext context) {
return InheritedUndo(
key: const Key('InheritedUndoSample'),
child: (Column(
children: [
Row(
children: [
ElevatedButton(onPressed: undo, child: Text("撤销")),
ElevatedButton(onPressed: redo, child: Text("重做")),
ElevatedButton(onPressed: add, child: Text("+")),
ElevatedButton(onPressed: reset, child: Text("重置")),
],
),
Row(
children: [
for (final val in values) Text("$val "),
],
),
Column(
children: [
Text("堆栈信息"),
Text("堆栈指针: ${InheritedUndo.of(context).undoStack.stackPointer}"),
Text("堆栈长度(可撤销): ${InheritedUndo.of(context).undoStack.stackSize}"),
Text("是否可撤销: ${InheritedUndo.of(context).undoStack.canUndo}"),
Text("是否可重做: ${InheritedUndo.of(context).undoStack.canRedo}"),
Row(
children: [
Text("["),
for (final c in InheritedUndo.of(context).undoStack.listCommands())
Text("${c.command.commandName}, "),
Text("]"),
],
)
],
),
],
)),
);
}
}
更多关于Flutter撤销操作插件nf_flutter_undo的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter撤销操作插件nf_flutter_undo的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是如何在Flutter项目中使用nf_flutter_undo
插件来实现撤销操作的示例代码。nf_flutter_undo
是一个用于管理撤销和重做操作的插件,可以帮助你在Flutter应用中轻松实现这些功能。
首先,你需要在你的pubspec.yaml
文件中添加该插件的依赖:
dependencies:
flutter:
sdk: flutter
nf_flutter_undo: ^最新版本号 # 请确保使用最新版本
然后运行flutter pub get
来安装依赖。
接下来,我们将编写一个简单的示例,展示如何使用nf_flutter_undo
插件。
示例代码
- 创建Flutter项目(如果还没有的话):
flutter create undo_example
cd undo_example
- 修改
main.dart
文件:
import 'package:flutter/material.dart';
import 'package:nf_flutter_undo/nf_flutter_undo.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Undo Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text('Flutter Undo Example'),
),
body: UndoProvider(
child: UndoExample(),
),
),
);
}
}
class UndoExample extends StatefulWidget {
@override
_UndoExampleState createState() => _UndoExampleState();
}
class _UndoExampleState extends State<UndoExample> with Undoable {
final List<String> _items = [];
final TextEditingController _controller = TextEditingController();
@override
Widget build(BuildContext context) {
final undoStack = UndoStack.of(context);
return Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Items:', style: TextStyle(fontSize: 18)),
Expanded(
child: ListView.builder(
itemCount: _items.length,
itemBuilder: (_, index) => ListTile(
title: Text(_items[index]),
),
),
),
SizedBox(height: 16),
TextField(
controller: _controller,
decoration: InputDecoration(labelText: 'New Item'),
),
SizedBox(height: 16),
ElevatedButton(
onPressed: () {
if (_controller.text.isNotEmpty) {
undoStack.withGroup(() {
setState(() {
_items.add(_controller.text);
});
_controller.clear();
});
}
},
child: Text('Add Item'),
),
SizedBox(height: 16),
Row(
children: [
ElevatedButton(
onPressed: () => undoStack.undo(),
child: Text('Undo'),
style: ButtonStyle(
overlayColor: MaterialStateProperty.all(Colors.red),
),
),
SizedBox(width: 16),
ElevatedButton(
onPressed: () => undoStack.redo(),
child: Text('Redo'),
style: ButtonStyle(
overlayColor: MaterialStateProperty.all(Colors.green),
),
),
],
),
],
),
);
}
}
解释
-
依赖注入:我们在
MyApp
的home
属性中使用了UndoProvider
来包装我们的UndoExample
组件。这确保了UndoStack
在整个UndoExample
组件中都是可用的。 -
状态管理:在
_UndoExampleState
中,我们使用了StatefulWidget
来管理我们的文本输入和列表项。 -
添加项目:当用户点击“Add Item”按钮时,我们会在
undoStack.withGroup
中包裹我们的状态更新代码。这确保了添加操作和清空文本输入被视为一个原子操作,可以一起撤销。 -
撤销和重做:我们提供了两个按钮来触发撤销和重做操作,分别调用
undoStack.undo()
和undoStack.redo()
。
这样,你就已经成功地在Flutter项目中集成了nf_flutter_undo
插件,并实现了基本的撤销和重做功能。希望这个示例对你有所帮助!