09 校验结果与提示信息

1. 需求中的状态数据分析

在上一篇中,已经准备好了数据和界面。本篇将介绍比较结果的校验,以及展示用户输入值和随机目标值的大小信息。点击确定时,可能的结果有 3 中,如下所示:

image.png


如下所示,是点击确定时不同情况下期望的界面效果;也就是说,界面的展现需要随着用户交互而变化。所以在当前需求之下,需要引入新的状态数据,用于控制界面的表现。

大了 小了 相等
1f08991dd5e4cefaffb40fa592d61f8.jpg 98a508b2b600181362cecaad6a5befd.jpg 1ae205f866d8a0f9560613ec736f936.jpg

这个状态数据将用于表示校验结果,该用什么类型呢?首先要明确一点:比较结果有三种情况: 大了小了相等 。其实只要某种数据类型包含三个值,都可以用于表示校验状态,只要逻辑正确即可,比如:

int 型: 
0: 大了
1: 小了
2: 相等

String 型: 
'big': 大了
'small': 小了
'equal': 相等

但如果用 intString 表示,首先必须提前做出规定。而对于不了解规定的人,在阅读时会增加理解的难度。如果这种类似的规定场景在一个项目里经常出现,就是一个个雷点,迟早会爆炸。其实 bool 类型的出现,就是为了避免用 01 整数来表示真假,带来语义上的难以理解。

能且仅能是一种语法上的约束,可以在根源上杜绝一些可能发生的错误。那问一个问题,什么类型有且仅有 3 个值?很多人会说 枚举,这确实可以,不过稍显麻烦。这里想用 bool?来表示三态,它有如下三个值:

null: 相等
true: 大了
false: 小了

分析完后,现在 _GuessPageState 里定义为变量 _isBig 作为状态数据,控制校验结果。默认为 null :

bool? _isBig;

2. 校验逻辑与状态数据的维护

校验逻辑算是比较简单的,对状态数据的维护可以称之为 业务逻辑,校验逻辑将在 _onCheck 回调中进行。上篇说过,这里可以得到目标值和输入值,输入值可以通过 int.tryParse 吧字符串转为整型。 有些小细节要注意一下:如果 _guessing 为 false ,表示游戏未开始;或输入的不是整数,此时应该不做响应,直接返回即可。

void _onCheck() {
  print("=====Check:目标数值:$_value=====${_guessCtrl.text}============");
  
  int? guessValue = int.tryParse(_guessCtrl.text);
  // 游戏未开始,或者输入非整数,无视
  if (!_guessing || guessValue == null) return;
  
  //猜对了
  if (guessValue == _value) {
    setState(() {
      _isBig = null;
      _guessing = false;
    });
    return;
  }
  
  // 猜错了
  setState(() {
    _isBig = guessValue > _value;
  });
}

如果猜对了,表示游戏结束,将 _guessing 置为 true、_isBig 置为 null ; 如果猜错了,通过 guessValue_value 的比较结果,为 _isBig 赋值。这就是对状态数据的维护过程。

image.png


3. 状态数据与界面构建逻辑

状态数据以及维护完毕,下面来看一下最后一步:使用 _isBig 状态控制界面的呈现。从最终效果,可以推断出_isBig 对界面的功效:

大了 小了 相等
1f08991dd5e4cefaffb40fa592d61f8.jpg 98a508b2b600181362cecaad6a5befd.jpg 1ae205f866d8a0f9560613ec736f936.jpg
  • 背景的色框提示,只有在大了或小了时才会出现,也就是说当 _isBig != null 时才会出现,对应下面代码的 69 行
  • 大了和小了是互斥的,不会同时出现,通过 Spacer 进行占位,大了时占下半;小了时占上半。

image.png

注: isBig! 是空安全的语法,如果一个可空对象 100% 确定非 null。可以通过 对象名! 表示 非空对象。 由于上面 if(_isBig) 才会走下方逻辑,所以使用处 100% 非空。


4.本章小结

到这里,猜数字简单版本就已经完成了。当前代码提交位置: guess_page.dart 你可以随机生成数字,在输入框中猜测数字,并校验猜测的值,给出提示。虽然是个小案例,但相比于计数器来说复杂了一些,额外维护了几个状态数据,界面布局上也更加复杂。是一个初学者进一步了解 Flutter 的好案例,把它吃透,会对你受益匪浅。

虽然现在可以完成猜数字需求,但是还有一点缺陷。比如当校验 小了, 下次校验还小时,由于 _isBig 的状态类没变,提示界面就没有任何变化(下左图)。如果用户的一个操作得不到反馈,体感上会觉得可能没点好;此时给予用户视觉上的反馈就会有比较好的体验,比如加一个动画效果(下左图):

无动画 有动画
95.gif 96.gif