likes
comments
collection
share

Flutter仿Boss-3.登录页

作者站长头像
站长
· 阅读数 3

效果

Flutter仿Boss-3.登录页

介绍

在Flutter应用程序中创建登录页面对于用户认证和参与至关重要。登录页面作为用户访问应用程序功能的入口。它应该提供无缝的体验,同时确保安全和隐私。这里仿Boss应用设计的登录页面,我们将创建一个登录页面,允许用户使用手机号码登录或注册。

小插曲

首先,让我们设置Flutter项目并创建一个登录页面组件。我们将使用GetX进行状态管理和UI更新。确保您在开发环境中安装了Flutter和GetX。

实现

1. 依赖项

确保您在pubspec.yaml文件中具有必要的依赖项:

dependencies:
  flutter:
    sdk: flutter
  get: ^4.6.2

2. 登录页小部件

创建一个名为login_page.dart的新文件,并定义LoginPage小部件。此小部件将包含登录页面的UI元素:

// login_page.dart
class LoginPage extends StatelessWidget {
  const LoginPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final logic = Get.find<LoginLogic>();
    return Scaffold(
      body: Container(
        padding: EdgeInsets.fromLTRB(24.w, 60.w, 24.w, 24.w),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              "手机号登录/注册",
              style: TextStyle(
                fontWeight: FontWeight.w500,
                fontSize: 30.sp,
                color: RC.text1Color,
              ),
            ),
            SizedBox(height: 6.w),
            Text(
              "首次验证通过即注册BOSS直聘账号",
              style: TextStyle(
                fontWeight: FontWeight.w500,
                fontSize: 14.sp,
                color: RC.text2Color,
              ),
            ),
            SizedBox(height: 10.w),
            Row(
              children: [
                Text(
                  "+86",
                  style: TextStyle(
                    fontSize: 16.sp,
                    color: Colors.black,
                  ),
                ),
                Icon(
                  Icons.keyboard_arrow_down,
                  size: 25.w,
                  color: Colors.black.withAlpha(70),
                ),
                Expanded(
                  child: TextField(
                    controller: logic.controller,
                    keyboardType: TextInputType.phone,
                    inputFormatters: [
                      FilteringTextInputFormatter.allow(RegExp(r'[0-9]')),
                    ],
                    style: TextStyle(color: Colors.black, fontSize: 18.sp),
                    onChanged: (value) {
                      logic.state.phoneNum.value = value;
                    },
                    decoration: InputDecoration(
                      hintText: '请输入您的手机号码',
                      // 设置 hintText
                      hintStyle: TextStyle(color: Colors.grey, fontSize: 18.sp),
                      // 设置 hintText 的颜色
                      border: InputBorder.none,
                      // 取消底部下划线
                      enabledBorder: const OutlineInputBorder(
                        borderSide: BorderSide(
                            color: Colors.transparent), // 取消输入框选中时的边框颜色
                      ),
                      focusedBorder: const OutlineInputBorder(
                        borderSide: BorderSide(
                            color: Colors.transparent), // 取消输入框获取焦点时的边框颜色
                      ),
                    ),
                  ),
                ),
              ],
            ),
            Divider(
              height: 1.w,
              color: Colors.grey,
            ),
            SizedBox(height: 16.w),
            Obx(
              () => InkWell(
                onTap: () {
                  logic.state.isAgree.value = !logic.state.isAgree.value;
                },
                child: Row(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Padding(
                      padding: const EdgeInsets.only(top: 5),
                      child: Icon(
                        logic.state.isAgree.value
                            ? Icons.check_circle
                            : Icons.circle_outlined,
                        size: 18.r,
                        color: logic.state.isAgree.value
                            ? RC.themeColor
                            : Colors.grey,
                      ),
                    ),
                    SizedBox(width: 5.w),
                    Expanded(
                      child:
                      RichText(
                        text: TextSpan(
                          text: '已阅读并同意',
                          style: const TextStyle(
                              color: Colors.black, fontSize: 16),
                          children: [
                            TextSpan(
                              text: '《BOSS直聘用户协议》',
                              style: const TextStyle(color: RC.themeColor),
                              recognizer: TapGestureRecognizer()
                                ..onTap = () {
                                  ToastUtil.show(msg: "跳转到BOSS直聘用户协议");
                                },
                            ),
                            const TextSpan(
                              text: ' 和 ',
                              style:
                                  TextStyle(color: Colors.black, fontSize: 16),
                            ),
                            TextSpan(
                              text: '《隐私政策》',
                              style: const TextStyle(color: RC.themeColor),
                              recognizer: TapGestureRecognizer()
                                ..onTap = () {
                                  ToastUtil.show(msg: "跳转到隐私政策");
                                },
                            ),
                            const TextSpan(
                              text: ',允许BOSS直聘统一管理本人账号信息',
                              style:
                                  TextStyle(color: Colors.black, fontSize: 16),
                            ),
                          ],
                        ),
                      ),
                    ),
                  ],
                ),
              ),
            ),
            Obx(
              () => InkWell(
                onTap: () {
                  logic.next(context);
                },
                child: Container(
                  height: 50.w,
                  alignment: Alignment.center,
                  margin: EdgeInsets.only(top: 20.w, bottom: 30.w),
                  decoration: BoxDecoration(
                      borderRadius: BorderRadius.all(Radius.circular(8.r)),
                      color: logic.state.phoneNum.isNotEmpty
                          ? RC.themeColor
                          : RC.themeColor.withAlpha(50)),
                  child: Text(
                    "下一步",
                    style: TextStyle(
                      fontSize: 20.sp,
                      fontWeight: FontWeight.w600,
                      color: Colors.white,
                    ),
                  ),
                ),
              ),
            ),
            Text(
              "接受不到短信",
              style: TextStyle(
                fontSize: 14.sp,
                color: Colors.grey,
              ),
            ),
            Expanded(
              child: Align(
                alignment: Alignment.bottomCenter,
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  mainAxisAlignment: MainAxisAlignment.end,
                  children: [
                    Text(
                      "或通过以下方式登录",
                      style: TextStyle(
                        fontSize: 14.sp,
                        color: Colors.grey,
                      ),
                    ),
                    SizedBox(height: 20.w),
                    InkWell(
                      onTap: () {
                        logic.wxLogin();
                      },
                      child: Image.asset(
                        R.login_wx_png,
                        width: 50.w,
                        height: 50.w,
                      ),
                    ),
                    SizedBox(height: 35.w),
                    Text(
                      "服务热线 举报监督电话 资质证照",
                      style: TextStyle(
                        fontSize: 14.sp,
                        color: Colors.grey,
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

3. 登录页逻辑

为登录页面创建一个逻辑类,用于处理业务逻辑和状态管理。定义处理用户输入和交互的方法:

// logic.dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';

import 'util/toast_util.dart';

class LoginLogic extends GetxController {
  final LoginState state = LoginState();
  final TextEditingController controller = TextEditingController();

  void wxLogin() {
    ToastUtil.show(msg: '微信登录');
  }

  void next(BuildContext context) {
    if (!state.isAgree.value) {
      showDialog(
        context: context,
        builder: (BuildContext context) {
          return AlertDialog(
            content: RichText(
              text: TextSpan(
                text: '请阅读并同意',
                style: const TextStyle(color: Colors.black, fontSize: 16),
                children: [
                  TextSpan(
                    text: '《BOSS直聘用户协议》',
                    style: const TextStyle(color: RC.themeColor),
                    recognizer: TapGestureRecognizer()
                      ..onTap = () {
                        ToastUtil.show(msg: "跳转到BOSS直聘用户协议");
                      },
                  ),
                  const TextSpan(
                    text: ' 和 ',
                    style: TextStyle(color: Colors.black, fontSize: 16),
                  ),
                  TextSpan(
                    text: '《隐私政策》',
                    style: const TextStyle(color: RC.themeColor),
                    recognizer: TapGestureRecognizer()
                      ..onTap = () {
                        ToastUtil.show(msg: "跳转到隐私政策");
                      },
                  ),
                  const TextSpan(
                    text: ',允许BOSS直聘统一管理本人账号信息',
                    style: TextStyle(color: Colors.black, fontSize: 16),
                  ),
                ],
              ),
            ),
            actions: <Widget>[
              TextButton(
                onPressed: () {
                  Navigator.of(context).pop();
                },
                child: const Text(
                  '拒绝',
                  style: TextStyle(
                    fontSize: 16,
                    color: RC.themeColor,
                  ),
                ),
              ),
              TextButton(
                onPressed: () {
                  state.isAgree.value = true;
                  Navigator.of(context).pop();
                },
                child: const Text(
                  '同意',
                  style: TextStyle(
                    fontSize: 16,
                    color: RC.themeColor,
                  ),
                ),
              ),
            ],
          );
        },
      );
      return;
    }
    ToastUtil.show(msg: '下一步');
  }
}

class LoginState {
  RxString phoneNum = "".obs;
  RxBool isAgree = false.obs;
}

4. 主程序入口

在您的主文件中,将登录页面添加到应用程序的路由中:

// main.dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';

import 'login_page.dart';
import 'logic.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      home: LoginPage(),
      initialBinding: BindingsBuilder(() {
        Get.lazyPut<LoginLogic>(() => LoginLogic());
      }),
    );
  }
}

结论

通过以上步骤,我们已经完成了Boss登录页面的UI效果。

Github

github.com/yixiaolunhui/flutter_project