设计给的效果如下:
拿到设计后,先把整体拆分成几个部分:
- “手机号输入框”,使用自定义的登录表单字段组件实现的输入框。
- “验证码输入框”,使用自定义的登录表单验证码组件和登录表单字段组件组合实现的输入框。
- “登录按钮”,使用自定义的涂鸦按钮组件实现的按钮。
然后就可以开始进行编码了。
第1步:绘制组件树
第2步:实现“手机号输入框”
首先引入需要的自定义组件,login_form_field.dart
文件是《Flutter布局锦囊---带彩条的文本字段》中的代码,login_form_code.dart
文件是《Flutter布局锦囊---验证码倒计时》中的代码,doodle_button.dart
文件是《Flutter布局锦囊---涂鸦风格按钮》中的代码。
import 'package:flutter/material.dart';
import 'login_form_field.dart';
import 'login_form_code.dart';
import '../common/doodle_button.dart';
/// 自定义的登录表单组件。
class LoginForm extends StatefulWidget {
@override
_LoginFormState createState() => _LoginFormState();
}
然后定义一些用来控制文本字段状态、验证码按钮状态的成员变量,同时把UI布局的基本轮廓描绘出来。
/// 与自定义的登录表单组件关联的状态子类。
class _LoginFormState extends State {
/// 手机号文本字段的控制器。
final _phoneController = TextEditingController();
/// 验证码文本字段的控制器。
final _codeController = TextEditingController();
/// 发送验证码按钮是否可用。
bool _codeAvailable = false;
/// 手机号文本字段是否符合格式。
bool _phoneActivation = false;
/// 验证码文本字段是否符合格式。
bool _codeActivation = false;
@override
Widget build(BuildContext context) {
return Row(
children: [
Expanded(
flex: 1,
child: SizedBox(),
),
Expanded(
flex: 8,
child: Column(
children: [
// TODO: 实现“手机号输入框”。
// TODO: 第3步:实现“验证码输入框”。
// TODO: 第4步:实现“登录按钮”。
],
),
),
Expanded(
flex: 1,
child: SizedBox(),
),
]
);
}
}
通过《Flutter布局锦囊---带彩条的文本字段》中实现的LoginFormField
组件,你可以迅速实现“手机号输入框”。
// TODO: 实现“手机号输入框”。
SizedBox(height: 20.0),
LoginFormField(
hintText: '请输入手机号',
textEditingController: _phoneController,
maxLength: 11,
minLength: 7,
legitimateCallback: () {
setState(() {
_phoneActivation = true;
_codeAvailable = true;
});
},
illegalCallback: () {
setState(() {
_phoneActivation = false;
_codeAvailable = false;
});
},
),
第3步:实现“验证码输入框”
通过《Flutter布局锦囊---带彩条的文本字段》中实现的LoginFormField
组件、《Flutter布局锦囊---验证码倒计时》中实现的LoginFormCode
组件,你可以迅速实现“验证码输入框”。
// TODO: 第3步:实现“验证码输入框”。
SizedBox(height: 30.0),
Stack(
children: [
LoginFormField(
hintText: '请输入验证码',
textEditingController: _codeController,
maxLength: 6,
minLength: 6,
legitimateCallback: () {
setState(() {
_codeActivation = true;
});
},
illegalCallback: () {
setState(() {
_codeActivation = false;
});
},
),
// 对齐(`Align`)组件,用于将其子项与其自身对齐,并根据子级的大小自行调整大小。
Align(
// 高度因子(`heightFactor`)属性,如果为非空值,则将其高度设置为子组件高度乘以此系数。
// 可以更大也可以小于`1.0`,但必须是正数。
heightFactor: 1.7,
// 对准(`alignment`)属性,如何调整子组件。
// 对准(`Alignment`)类的中心右边(`centerRight`)常量,沿右边的中心点对准。
alignment: Alignment.centerRight,
child: LoginFormCode(
countdown: 60,
available: _codeAvailable,
onTapCallback: () {
print(_codeController.text);
},
),
),
],
),
第4步:实现“登录按钮”
最后,通过《Flutter布局锦囊---涂鸦风格按钮》中的DoodleButton
组件,迅速实现“登录按钮”。
// TODO: 第4步:实现“登录按钮”。
SizedBox(height: 48.0),
DoodleButton(
promptText: '登录',
activation: _codeActivation && _phoneActivation,
onTapCallback: (){
print('点击了“登录”按钮');
},
),