登录界面实现
效果图
讲解:
使用 GetX 框架实现依赖注入
延迟了实例化过程,只有在需要时才会创建对象
class SignInBinding implements Bindings {
@override
void dependencies() {
Get.lazyPut<SignInController>(() => SignInController());
}
}
@override
void dependencies() {
Get.lazyPut<SignInController>(() => SignInController());
}
}
SignInController:管理登录界面的状态和业务逻辑
class SignInController extends GetxController {
final state = SignInState();
SignInController();
// email的控制器
final TextEditingController emailController = TextEditingController();
// 密码的控制器
final TextEditingController passController = TextEditingController();
// 跳转 注册界面
handleNavSignUp() {
Get.toNamed(AppRoutes.SIGN_UP);
}
// 忘记密码
handleFogotPassword() {
toastInfo(msg: '忘记密码');
}
// 执行登录操作
handleSignIn() async {
UserLoginRequestEntity params = UserLoginRequestEntity(
email: emailController.value.text,
password: duSHA256(passController.value.text),
);
UserLoginResponseEntity userProfile = await UserAPI.login(
params: params,
);
UserStore.to.saveProfile(userProfile);
Get.offAndToNamed(AppRoutes.Application);
}
@override
void dispose() {
emailController.dispose();
passController.dispose();
super.dispose();
}
}
final state = SignInState();
SignInController();
// email的控制器
final TextEditingController emailController = TextEditingController();
// 密码的控制器
final TextEditingController passController = TextEditingController();
// 跳转 注册界面
handleNavSignUp() {
Get.toNamed(AppRoutes.SIGN_UP);
}
// 忘记密码
handleFogotPassword() {
toastInfo(msg: '忘记密码');
}
// 执行登录操作
handleSignIn() async {
UserLoginRequestEntity params = UserLoginRequestEntity(
email: emailController.value.text,
password: duSHA256(passController.value.text),
);
UserLoginResponseEntity userProfile = await UserAPI.login(
params: params,
);
UserStore.to.saveProfile(userProfile);
Get.offAndToNamed(AppRoutes.Application);
}
@override
void dispose() {
emailController.dispose();
passController.dispose();
super.dispose();
}
}
代码的模块化和组织管理
library sign_in;
export './state.dart';
export './controller.dart';
export './bindings.dart';
export './view.dart';
export './state.dart';
export './controller.dart';
export './bindings.dart';
export './view.dart';
实现响应式状态管理。
import 'package:get/get.dart';
class SignInState {
final _obj = ''.obs;
set obj(value) => _obj.value = value;
get obj => _obj.value;
// SignInState() {}
}
class SignInState {
final _obj = ''.obs;
set obj(value) => _obj.value = value;
get obj => _obj.value;
// SignInState() {}
}
ui界面实现
Widget _buildLogo() {
return Container(
width: 110.w,
margin: EdgeInsets.only(top: (40 + 44.0).h), // 顶部系统栏 44px
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
height: 76.w,
width: 76.w,
margin: EdgeInsets.symmetric(horizontal: 15.w),
child: Stack(
alignment: Alignment.center,
children: [
Positioned(
left: 0,
top: 0,
right: 0,
child: Container(
height: 76.w,
decoration: BoxDecoration(
color: AppColors.primaryBackground,
boxShadow: const [
Shadows.primaryShadow,
],
borderRadius: BorderRadius.all(
Radius.circular((76 * 0.5).w)), // 父容器的50%
),
child: Container(),
),
),
Positioned(
top: 13.w,
child: Image.asset(
"assets/images/a.png",
fit: BoxFit.none,
),
),
],
),
),
Container(
margin: EdgeInsets.only(top: 15.h),
child: Text(
"今日",
textAlign: TextAlign.center,
style: TextStyle(
color: AppColors.primaryText,
fontFamily: "Montserrat",
fontWeight: FontWeight.w600,
fontSize: 24.sp,
height: 1,
),
),
),
Text(
"news",
textAlign: TextAlign.center,
style: TextStyle(
color: AppColors.primaryText,
fontFamily: "Avenger",
fontWeight: FontWeight.w400,
fontSize: 24.sp,
height: 1,
),
),
],
),
);
}
return Container(
width: 110.w,
margin: EdgeInsets.only(top: (40 + 44.0).h), // 顶部系统栏 44px
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
height: 76.w,
width: 76.w,
margin: EdgeInsets.symmetric(horizontal: 15.w),
child: Stack(
alignment: Alignment.center,
children: [
Positioned(
left: 0,
top: 0,
right: 0,
child: Container(
height: 76.w,
decoration: BoxDecoration(
color: AppColors.primaryBackground,
boxShadow: const [
Shadows.primaryShadow,
],
borderRadius: BorderRadius.all(
Radius.circular((76 * 0.5).w)), // 父容器的50%
),
child: Container(),
),
),
Positioned(
top: 13.w,
child: Image.asset(
"assets/images/a.png",
fit: BoxFit.none,
),
),
],
),
),
Container(
margin: EdgeInsets.only(top: 15.h),
child: Text(
"今日",
textAlign: TextAlign.center,
style: TextStyle(
color: AppColors.primaryText,
fontFamily: "Montserrat",
fontWeight: FontWeight.w600,
fontSize: 24.sp,
height: 1,
),
),
),
Text(
"news",
textAlign: TextAlign.center,
style: TextStyle(
color: AppColors.primaryText,
fontFamily: "Avenger",
fontWeight: FontWeight.w400,
fontSize: 24.sp,
height: 1,
),
),
],
),
);
}
const Spacer(),
这个
Spacer
控件会在布局中占据可用的空间,它通常用于调整子控件之间的间距或者使布局中的控件充满剩余空间。// 登录表单
Widget _buildInputForm() {
return Container(
width: 295.w,
// height: 204,
margin: EdgeInsets.only(top: 49.h),
child: Column(
children: [
// email input
inputTextEdit(
controller: controller.emailController,
keyboardType: TextInputType.emailAddress,
hintText: "邮箱",
marginTop: 0,
// autofocus: true,
),
// password input
inputTextEdit(
controller: controller.passController,
keyboardType: TextInputType.visiblePassword,
hintText: "密码",
isPassword: true,
),
// 注册、登录 横向布局
Container(
height: 44.h,
margin: EdgeInsets.only(top: 15.h),
child: Row(
children: [
// 注册
btnFlatButtonWidget(
onPressed: controller.handleNavSignUp,
gbColor: AppColors.thirdElement,
title: "注册",
),
const Spacer(),
// 登录
btnFlatButtonWidget(
onPressed: controller.handleSignIn,
gbColor: AppColors.primaryElement,
title: "登录",
),
],
),
),
// Spacer(),
// Fogot password
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: TextButton(
onPressed: controller.handleFogotPassword,
child: Text(
"忘记密码?",
textAlign: TextAlign.center,
style: TextStyle(
color: AppColors.secondaryElementText,
fontFamily: "Avenger",
fontWeight: FontWeight.w400,
fontSize: 16.sp,
height: 1, // 设置下行高,否则字体下沉
),
),
),
),
],
),
);
}
Widget _buildInputForm() {
return Container(
width: 295.w,
// height: 204,
margin: EdgeInsets.only(top: 49.h),
child: Column(
children: [
// email input
inputTextEdit(
controller: controller.emailController,
keyboardType: TextInputType.emailAddress,
hintText: "邮箱",
marginTop: 0,
// autofocus: true,
),
// password input
inputTextEdit(
controller: controller.passController,
keyboardType: TextInputType.visiblePassword,
hintText: "密码",
isPassword: true,
),
// 注册、登录 横向布局
Container(
height: 44.h,
margin: EdgeInsets.only(top: 15.h),
child: Row(
children: [
// 注册
btnFlatButtonWidget(
onPressed: controller.handleNavSignUp,
gbColor: AppColors.thirdElement,
title: "注册",
),
const Spacer(),
// 登录
btnFlatButtonWidget(
onPressed: controller.handleSignIn,
gbColor: AppColors.primaryElement,
title: "登录",
),
],
),
),
// Spacer(),
// Fogot password
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: TextButton(
onPressed: controller.handleFogotPassword,
child: Text(
"忘记密码?",
textAlign: TextAlign.center,
style: TextStyle(
color: AppColors.secondaryElementText,
fontFamily: "Avenger",
fontWeight: FontWeight.w400,
fontSize: 16.sp,
height: 1, // 设置下行高,否则字体下沉
),
),
),
),
],
),
);
}
// 第三方登录
Widget _buildThirdPartyLogin() {
return Container(
width: 295.w,
margin: EdgeInsets.only(bottom: 40.h),
child: Column(
children: <Widget>[
// title
Text(
"其他登录",
textAlign: TextAlign.center,
style: TextStyle(
color: AppColors.primaryText,
fontFamily: "Avenger",
fontWeight: FontWeight.w400,
fontSize: 16.sp,
),
),
// 按钮
Padding(
padding: EdgeInsets.only(top: 20.h),
child: Row(
children: <Widget>[
btnFlatButtonBorderOnlyWidget(
onPressed: () {},
width: 88,
iconFileName: "twitter",
),
const Spacer(),
btnFlatButtonBorderOnlyWidget(
onPressed: () {},
width: 88,
iconFileName: "google",
),
const Spacer(),
btnFlatButtonBorderOnlyWidget(
onPressed: () {},
width: 88,
iconFileName: "facebook",
),
],
),
),
],
),
);
}
Widget _buildThirdPartyLogin() {
return Container(
width: 295.w,
margin: EdgeInsets.only(bottom: 40.h),
child: Column(
children: <Widget>[
// title
Text(
"其他登录",
textAlign: TextAlign.center,
style: TextStyle(
color: AppColors.primaryText,
fontFamily: "Avenger",
fontWeight: FontWeight.w400,
fontSize: 16.sp,
),
),
// 按钮
Padding(
padding: EdgeInsets.only(top: 20.h),
child: Row(
children: <Widget>[
btnFlatButtonBorderOnlyWidget(
onPressed: () {},
width: 88,
iconFileName: "twitter",
),
const Spacer(),
btnFlatButtonBorderOnlyWidget(
onPressed: () {},
width: 88,
iconFileName: "google",
),
const Spacer(),
btnFlatButtonBorderOnlyWidget(
onPressed: () {},
width: 88,
iconFileName: "facebook",
),
],
),
),
],
),
);
}
// 注册按钮
Widget _buildSignupButton() {
return Container(
margin: EdgeInsets.only(bottom: 20.h),
child: btnFlatButtonWidget(
onPressed: controller.handleNavSignUp,
width: 294,
gbColor: AppColors.secondaryElement,
fontColor: AppColors.primaryText,
title: "注册",
fontWeight: FontWeight.w500,
fontSize: 16,
),
);
}
Widget _buildSignupButton() {
return Container(
margin: EdgeInsets.only(bottom: 20.h),
child: btnFlatButtonWidget(
onPressed: controller.handleNavSignUp,
width: 294,
gbColor: AppColors.secondaryElement,
fontColor: AppColors.primaryText,
title: "注册",
fontWeight: FontWeight.w500,
fontSize: 16,
),
);
}
页面的构建
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
body: Center(
child: Column(
children: <Widget>[
_buildLogo(),
_buildInputForm(),
const Spacer(),
_buildThirdPartyLogin(),
_buildSignupButton(),
],
),
),
);
}
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
body: Center(
child: Column(
children: <Widget>[
_buildLogo(),
_buildInputForm(),
const Spacer(),
_buildThirdPartyLogin(),
_buildSignupButton(),
],
),
),
);
}
resizeToAvoidBottomInset: false
设置了页面不随键盘弹出而重新调整大小,这样可以避免键盘弹出时导致页面内容被遮挡。
评论
发表评论