# 优化短信验证码逻辑

# 禁止获取验证码事件误触

主要优化counter_button.dart的逻辑:

class _CounterButtonState extends State<CounterButton> {
  String _msg = '获取验证码';
  NumberCount _numberCount = NumberCount();

  
  Widget build(BuildContext context) {
    return StreamBuilder(
        stream: _numberCount.stream,
        builder: (context, snapshot) {
          // ...
          return ElevatedButton(
            // ...
            onPressed: () {
              // 优化点击事件,当按钮不可点击时,把onPressed事件进行屏蔽
              if (!(widget.active && _numberCount.avaliable)) {
                return;
              }
              _numberCount.start();
              widget.onPressed!();
            },
          );
        });
  }
}

# 键盘相关

# 模拟键盘

在mac上模拟键盘的弹出:

image-20220122145824144

在顶部的菜单点选I/O->Keyboard->Connect Hardware Keyboard取消掉,就可以弹出模拟键盘了:

image-20220122145948637

# 键盘高度溢出

除了键盘可能会溢出,页面上的元素也可能会导致溢出(空间不够),或者叠在一起了,提示xxx OVERFLOWED BY xx PIXELS。知道了原因之后,具体问题具体分析:

键盘溢出,是由于首页整个内容不能滚动。

解决方案:

// 使用SingleChildScrollView
class _HomePageState extends State<HomePage> {
  
  Widget build(BuildContext context) {
    return SafeArea(
      // 1.Column -> logo + form
      // 2.如何引用图片 -> 图片圆角
      child: SingleChildScrollView(
        child: Column(
          children: [
            // ...
            // 这个是封装的登录组件
            LoginForm(),
          ],
        ),
      ),
    );
  }
}

# 键盘颜色背景

# 方案一

通过设置TextField

TextField(
  focusNode: currentFocusNode,
  controller: controller,
  // 设置 keyboardAppearance, light为浅色,默认为 dark 深色
  // keyboardAppearance: Brightness.light,
  decoration: InputDecoration(
    counterText: "",
    prefixIcon: Icon(
      MyIcons.person,
      color: Colors.black54,
      size: 26,
    ),
  ),
  // ...

缺点:

针对于所有的键盘都需要设置,比较麻烦。

# 方案二

一劳永逸的作法,在main.dart中设置主题:

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    // CuperinoApp
    return MaterialApp(
      theme: ThemeData(
        brightness: Brightness.light,
        primaryColorBrightness: Brightness.light,
      ),
      home: Scaffold(
        appBar: AppBar(),
        // 2. SafeArea
        body: HomePage(),
      ),
    );
    // return MaterialApp(
    //   home: Scaffold(
    //     appBar: AppBar(),
    //     body: Container(
    //       child: Text(
    //         'toimc社区',
    //         textDirection: TextDirection.ltr,
    //       ),
    //     ),
    //   ),
    // );
  }
}

# 如何自动聚焦输入框

需要借助到FocusNode,修改login/login_form.dart文件中的LoginFormState

// 新建两个FocusNode,用于控制聚焦
FocusNode currentFocusNode = FocusNode();
FocusNode focusNode = FocusNode();


// 调整手机号 + 验证码部分的输入的Textfield
TextField(
    focusNode: currentFocusNode,
    // ...
),

TextField(
    focusNode: focusNode,
    // ...
),

自动聚焦如何实现:

// 定义私有方法
_changeFocus(FocusNode focusNodeNext) {
  // 判断一下,current是否被聚焦,取消聚焦 -> 聚焦新的输入框
  FocusNode currentFocus = FocusScope.of(context);
  if (!currentFocus.hasPrimaryFocus) {
    currentFocus.unfocus();
  }
  focusNodeNext.requestFocus();
}

输入手机号之后,点击获取验证码:

// Positioned
// 1.页面按钮状态 -> 有状态组件如何设置页面状态
// 2.倒计时逻辑 -> stream
Positioned(
  right: 10.0,
  child: CounterButton(
    active: _active,
    onPressed: () async {
      _changeFocus(focusNode);
      userService.sendCode(controller.text);
    },
  ),
)

# 其他技巧

  • 如何设置键盘的类型?

    可以设置TextField中的keyboardType,比如keyboardType: TextInputType.number,这样键盘弹出后就只能输入数字类型的数据了。

  • 如何删除Input输入框后面的文字计数?

    可以在decoration部分设置InputDecoration中的counterText为空字符串。