zwvista

导航

ReactiveX 学习笔记(35)使用 RxDart + RxCommand 进行 GUI 编程

课题

  1. 程序界面由3个文本编辑框和1个文本标签组成。
  2. 要求文本标签实时显示3个文本编辑框所输入的数字之和。
  3. 文本编辑框输入的不是合法数字时,将其值视为0。
  4. 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),
                  ),
                ]),
              ]),
        ),
      ),
    );
  }
}

posted on 2021-04-03 05:25  zwvista  阅读(176)  评论(0编辑  收藏  举报