一、前言
前面了解了Flutter的适配原理级及适配方案,接下来我们进行一个实战,开发一个登录界面,效果图如下:
二、代码实践
2.1 LoginPage
这里LoginPage使用StatefulWidget来实现:
class LoginPage extends StatefulWidget {
const LoginPage({Key? key}) : super(key: key);
@override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: EdgeInsets.symmetric(horizontal: 16.dp),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
),
),
);
}
}
2.2 为Column添加内容
欢迎登录和头部有一定的距离,这里使用SizedBox在占位
children: [
SizedBox(
height: 80.dp,
),
]
为了children代码开起来简洁,我们将每一行的内容单独使用方法或者widget实现,
2.2.1 添加输入文本
children: [
SizedBox(
height: 80.dp,
),
buildTopWidget(),
],
Widget buildTopWidget() {
return Text(
'您好,欢迎登录',
style: TextStyle(fontSize: 28.sp, fontWeight: FontWeight.w800),
);
}
2.2.2 添加账户输入框
children: [
SizedBox(
height: 80.dp,
),
buildTopWidget(),
SizedBox(
height: 20.dp,
),
buildAccountInputWidget(accountController),
],
Widget buildAccountInputWidget(TextEditingController controller) {
return TextField(
controller: controller,
decoration: const InputDecoration(
labelText: "手机号",
),
style: TextStyle(fontSize: 16.sp),
keyboardType: TextInputType.phone,
);
}
2.2.2 添加密码输入框
children: [
SizedBox(
height: 80.dp,
),
buildTopWidget(),
SizedBox(
height: 20.dp,
),
buildAccountInputWidget(accountController),
SizedBox(
height: 20.dp,
),
buildPasswordInputWidget(pwdController),
],
Widget buildPasswordInputWidget(TextEditingController controller) {
return TextField(
controller: controller,
obscureText: true,
decoration: const InputDecoration(labelText: "用户密码"),
style: TextStyle(fontSize: 16.sp),
);
}
2.2.3 添加用户协议
用户协议和隐私政策包含了一个复选框和文本描述,单独剥离一个widget来使用。
children: [
SizedBox(
height: 80.dp,
),
buildTopWidget(),
SizedBox(
height: 20.dp,
),
buildAccountInputWidget(accountController),
SizedBox(
height: 20.dp,
),
buildPasswordInputWidget(pwdController),
SizedBox(
height: 10.dp,
),
PrivacyWidget(
onChanged: (value) {
checked = value;
},
),
],
//用户协议和隐私政策
class PrivacyWidget extends StatefulWidget {
const PrivacyWidget({Key? key, required this.onChanged}) : super(key: key);
final ValueChanged<bool?> onChanged;
@override
_PrivacyWidgetState createState() => _PrivacyWidgetState();
}
class _PrivacyWidgetState extends State<PrivacyWidget> {
bool? checked = false;
@override
Widget build(BuildContext context) {
return Row(
children: [
Checkbox(
value: checked,
onChanged: (value) {
widget.onChanged(value);
setState(() {
checked = value;
});
}),
Text(
'同意',
style: TextStyle(fontSize: 14.sp),
),
Text(
'<服务协议>',
style: TextStyle(fontSize: 14.sp, color: Colors.blue),
),
Text(
'和',
style: TextStyle(fontSize: 14.sp),
),
Text('<隐私政策>', style: TextStyle(fontSize: 14.sp, color: Colors.blue)),
],
);
}
}
这里Checkbox的状态变化的使用回调的方式,一遍外部进行状态管理。
2.2.4 添加登录按钮
children: [
SizedBox(
height: 80.dp,
),
buildTopWidget(),
SizedBox(
height: 20.dp,
),
buildAccountInputWidget(accountController),
SizedBox(
height: 20.dp,
),
buildPasswordInputWidget(pwdController),
SizedBox(
height: 10.dp,
),
PrivacyWidget(
onChanged: (value) {
checked = value;
},
),
SizedBox(
height: 50.dp,
),
buildButton(_buttonCallback),
],
2.2.5 添加相关widget的事件处理
相关wideget的回调处理,主要在_LoginPageState中完成。
class _LoginPageState extends State<LoginPage> {
late VoidCallback _buttonCallback;
late TextEditingController accountController;
late TextEditingController pwdController;
bool? checked = false;
@override
void initState() {
super.initState();
_buttonCallback = () {
_handleLogin();
};
accountController = TextEditingController();
pwdController = TextEditingController();
}
@override
void dispose() {
accountController.dispose();
pwdController.dispose();
super.dispose();
}
void _handleLogin() {
String account = accountController.value.text;
String pwd = pwdController.value.text;
if (account.isEmpty) {
toast.showToast(msg: '请输入手机号');
return;
}
if (pwd.isEmpty) {
toast.showToast(msg: '请输入密码');
return;
}
if (!checked!) {
toast.showToast(msg: '请同意用户协议和隐私政策');
return;
}
_skipToMain();
}
}
2.2.6 最终效果图
三、最后
- 目前只是完成了UI的开发,具体的业务逻辑还未实现
- 跟多的细节还未完善,需要后期进一步实现
- 接下里要做的就是界面跳转,Flutter里面叫路由,下一步我们了解Flutter中的路由和导航功能。