Flutter布局锦囊---绑定手机页

设计给的效果如下:

UI布局图

拿到设计后,先把整体拆分成几个部分:

  1. “顶部导航栏”,标题+取消按钮+跳过按钮的应用栏。
  2. “手机号输入框”,用于获取手机号码的圆角边框输入字段。
  3. “验证码输入框”,用于获取验证码的圆角边框输入字段,还包括获取验证码的按钮。
  4. “提交按钮”,在满足条件后让用户点击的提交按钮。

然后就可以开始进行编码了。

第1步:绘制组件树

绑定手机页的组件树

第2步:实现“顶部导航栏”

下面的代码导入了一堆东西,大概说一下都是些什么吧。../common/first_navigation.dart《Flutter布局锦囊---简单的应用栏》,不过针对这个需求做了一些小改动。../common/doodle_button.dart《Flutter布局锦囊---涂鸦风格按钮》../common/round_form_field.dart《Flutter布局锦囊---圆框的表单字段》widgets/login_form_code.dart《Flutter布局锦囊---验证码倒计时》

import 'package:flutter/material.dart';
import '../common/first_navigation.dart';
import '../common/doodle_button.dart';
import '../common/round_form_field.dart';
import 'widgets/login_form_code.dart';

/// 自定义的绑定页面组件。
class Binding extends StatefulWidget {

  @override
  _BindingState createState() => _BindingState();
}

下面代码的主体是《Flutter布局锦囊---简单的应用栏》中自定义的一级导航(firstNavigation)组件,不过这里你要把行动(actions)和主导(leading)属性设置成可以配置的,如果没有则为空值(null)。

/// 与自定义的绑定页面组件关联的状态子类。
class _BindingState extends State<Binding> {
  /// 手机号表单字段的控制器。
  final _phoneController = TextEditingController();
  /// 验证码表单字段的控制器。
  final _codeController = TextEditingController();
  /// 发送验证码按钮是否可用。
  bool _codeAvailable = false;
  /// 手机号表单字段是否符合格式。
  bool _phoneActivation = false;
  /// 验证码表单字段是否符合格式。
  bool _codeActivation = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: firstNavigation(
        '绑定手机',
        // 墨水瓶(`InkWell`)组件,响应触摸的矩形区域。
        leading: InkWell(
          child: Text(
            '  取消  ',
            style: TextStyle(
              color: Color(0xFF777777),
              fontSize: 16.0,
            ),
          ),
          onTap: (){
            Navigator.of(context).pop();
          },
        ),
        actions: InkWell(
          child: Text(
            '  跳过  ',
            style: TextStyle(
              color: Color(0xFFFF6B47),
              fontSize: 16.0,
            ),
          ),
          onTap: (){
            Navigator.of(context).pushNamedAndRemoveUntil('/', (Route<dynamic> route) => false);
          },
        ),
      ),
      body: ListView(
        padding: EdgeInsets.symmetric(horizontal: 20.0),
        children: <Widget>[
          // TODO: 第3步:实现“手机号输入框”
          // TODO: 第4步:实现“验证码输入框”
          // TODO: 第5步:实现“提交按钮”
        ],
      ),
    );
  }
}

第3步:实现“手机号输入框”

下面代码的主体是《Flutter布局锦囊---圆框的表单字段》中自定义的圆框表单字段(RoundFormField)组件。这个就可以直接使用了,不用像上面那一步修改代码。

          // TODO: 第3步:实现“手机号输入框”
          Container(
            padding: EdgeInsets.symmetric(vertical: 20.0),
            child: Text(
              '绑定手机后可以直接使用手机号码登录',
              style: TextStyle(
                color: Color(0xFF777777),
                fontSize: 14.0,
              ),
            ),
          ),
          RoundFormField(
            hintText: '请输入手机号',
            textEditingController: _phoneController,
            checkCallback: (value){
              if(value.trim().length == 11) {
                _codeAvailable = true;
                _phoneActivation = true;
              } else {
                _codeAvailable = false;
                _phoneActivation = false;
              }
              setState(() {});
            },
          ),
          SizedBox(height: 20),

第4步:实现“验证码输入框”

下面代码的主体是《Flutter布局锦囊---圆框的表单字段》中自定义的圆框表单字段(RoundFormField)组件,再佐以《Flutter布局锦囊---验证码倒计时》中自定义的倒计时(LoginFormCode)组件作为调料。它们共同完成了验证码输入框。

          // TODO: 第4步:实现“验证码输入框”
          Stack(
            children: <Widget>[
              RoundFormField(
                hintText: '请输入验证码',
                textEditingController: _codeController,
                checkCallback: (value){
                  if(value.trim().length == 6) {
                    _codeActivation = true;
                  } else {
                    _codeActivation = false;
                  }
                  setState(() {});
                },
              ),
              // 对齐(`Align`)组件,用于将其子项与其自身对齐,并根据子级的大小自行调整大小。
              Align(
                // 高度因子(`heightFactor`)属性,如果为非空值,则将其高度设置为子组件高度乘以此系数。
                heightFactor: 2.0,
                // 对准(`alignment`)属性,如何调整子组件。
                alignment: Alignment.centerRight,
                child: LoginFormCode(
                  countdown: 60,
                  available: _codeAvailable,
                  onTapCallback: () {
                    // 根据需求写提交的过程以及后续操作~
                  },
                ),
              ),
            ],
          ),

第5步:实现“提交按钮”

下面代码的主体是《Flutter布局锦囊---涂鸦风格按钮》中自定义的涂鸦按钮(DoodleButton)组件,注意要通过setState(() {});来改变按钮的可点击状态。

        // TODO: 第5步:实现“提交按钮”
          SizedBox(height: 40),
          DoodleButton(
            promptText: '绑定',
            activation: _phoneActivation && _codeActivation,
            onTapCallback: (){
              setState(() {
                _codeActivation = false;
              });
              // 根据需求写提交的过程以及后续操作~
              setState(() {
                _codeActivation = true;
              });
            },
          ),

第6步:还原效果

绑定手机页的还原效果
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容

  • 设计给的效果如下: 拿到设计后,先把整体拆分成几个部分: “手机号输入框”,使用自定义的登录表单字段组件实现的输入...
    何小有阅读 1,139评论 0 6
  • 设计给的效果如下: 拿到设计后,先把整体拆分成几个部分: “运营位”,使用自定义的旋转木马滑块组件实现可以滚动的运...
    何小有阅读 2,687评论 0 5
  • 设计给的效果如下: 拿到设计后,先把整体拆分成几个部分: “用户昵称输入”,获取用户输入的昵称信息。 “用户头像选...
    何小有阅读 1,480评论 1 11
  • Flutter中一切皆组件(Widget),一个Flutter项目可以看作是大量的Widget堆砌而成,类似于堆乐...
    芝麻酱的简书阅读 1,161评论 0 7
  • 这两天忙坏了,星期三去上片区的公开课,当时想着好吧,语文不是我的本专业,我也我也抱着不太可能的态度,不过我也有尽力...
    Eva华阅读 229评论 0 0