ReactiveX 学习笔记(35)使用 RxDart + RxCommand 进行 GUI 编程
课题
- 程序界面由3个文本编辑框和1个文本标签组成。
- 要求文本标签实时显示3个文本编辑框所输入的数字之和。
- 文本编辑框输入的不是合法数字时,将其值视为0。
- 3个文本编辑框的初值分别为1,2,3。
创建工程
Flutter 安装完毕之后执行以下命令创建工程
flutter create rx_example
打开 Android Studio,File / Open...
选择 rx_example 文件夹以打开 Flutter 工程。
添加依赖
打开 pubspec.yaml 文件,在 dependencies: 下添加对 RxDart 和 RxCommand 的依赖
dependencies:
flutter:
sdk: flutter
rxdart: 0.25.0
rx_command: ^5.3.0
点击 Pub get 下载所依赖的包
ViewModel
在 lib 文件夹下添加 rx_example_viewmodel.dart 文件,内容如下
import 'package:rx_command/rx_command.dart';
import 'package:rxdart/rxdart.dart';
class RxExampleViewModel {
final number1 = RxCommand.createSync((String v) => v, initialLastResult: "1");
final number2 = RxCommand.createSync((String v) => v, initialLastResult: "2");
final number3 = RxCommand.createSync((String v) => v, initialLastResult: "3");
RxCommand<void, String> result;
RxExampleViewModel() {
int f(String s) => int.tryParse(s) ?? 0;
result = RxCommand.createFromStream((_) => CombineLatestStream.combine3(
number1.startWith(number1.lastResult),
number2.startWith(number2.lastResult),
number3.startWith(number3.lastResult),
(String a, String b, String c) => (f(a) + f(b) + f(c)).toString()));
result(result.lastResult);
}
}
Main
最后打开 main.dart,将内容改为
import 'package:flutter/material.dart';
import 'package:rx_example/rx_example_viewmodel.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: RxExamplePage(title: 'Rx Example Page'),
);
}
}
class RxExamplePage extends StatefulWidget {
RxExamplePage({Key key, this.title}) : super(key: key);
final String title;
@override
_RxExamplePageState createState() => _RxExamplePageState();
}
class _RxExamplePageState extends State<RxExamplePage> {
final vm = RxExampleViewModel();
TextEditingController number1Ctrl;
TextEditingController number2Ctrl;
TextEditingController number3Ctrl;
_RxExamplePageState() {
number1Ctrl = TextEditingController(text: vm.number1.lastResult);
number2Ctrl = TextEditingController(text: vm.number2.lastResult);
number3Ctrl = TextEditingController(text: vm.number3.lastResult);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Container(
width: 150,
child: Table(
columnWidths: {0: FractionColumnWidth(.2)},
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
children: [
TableRow(children: [
Container(),
TextField(
controller: number1Ctrl,
textAlign: TextAlign.end,
onChanged: vm.number1)
]),
TableRow(children: [
Container(),
TextField(
controller: number2Ctrl,
textAlign: TextAlign.end,
onChanged: vm.number2)
]),
TableRow(children: [
Center(child: Text("+")),
TextField(
controller: number3Ctrl,
textAlign: TextAlign.end,
onChanged: vm.number3)
]),
TableRow(children: [
Center(child: Text("=")),
StreamBuilder(
stream: vm.result,
builder: (context, snapshot) =>
Text(vm.result.lastResult, textAlign: TextAlign.end),
),
]),
]),
),
),
);
}
}