有了登录页面 怎么可能没有注册页面呢 所以它来了

1.注册页面的开发先看截图效果

该页面包含手机号、密码、验证码输入,短信验证码发送与倒计时,表单验证,隐私政策同意与否。

2.功能部分

注册页面主要包含以下几个部分:

标题区域:用户注册标题

手机号输入框:带图标的手机号输入

密码输入框:支持显示/隐藏密码

验证码输入框:验证码输入 + 获取验证码按钮(带倒计时)

短信帮助链接:解决验证码问题的帮助信息

操作按钮:返回登录 + 立即注册

隐私政策同意:复选框 + 隐私政策页面

3.状态

class RegisterPage extends StatefulWidget {
  const RegisterPage({super.key});

  @override
  State<RegisterPage> createState() => _RegisterPageState();
}

class _RegisterPageState extends State<RegisterPage> {
  // 输入控制器
  final TextEditingController _phoneController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();
  final TextEditingController _codeController = TextEditingController();
  
  // 状态变量
  bool _obscurePassword = true;      // 密码是否隐藏
  bool _agreedToPrivacy = false;     // 是否同意隐私政策
  int _countdown = 0;                // 验证码倒计时

  @override
  void dispose() {
    _phoneController.dispose();
    _passwordController.dispose();
    _codeController.dispose();
    super.dispose();
  }
}

代码解释

三个TextEditingController分别为手机号、密码、验证码输入

_countdown是验证码按钮的倒计时状态

在 dispose中释放资源

4.页面整体代码结构

@override
Widget build(BuildContext context) {
  return Scaffold(
    backgroundColor: Colors.white,
    body: SafeArea(
      child: SingleChildScrollView(
        padding: const EdgeInsets.symmetric(horizontal: 32),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            const SizedBox(height: 60),
            // 标题
            const Text(
              '用户注册',
              style: TextStyle(
                fontSize: 28,
                fontWeight: FontWeight.bold,
                color: Color(0xFF1F2937),
              ),
              textAlign: TextAlign.center,
            ),
            const SizedBox(height: 60),
            _buildPhoneInput(),
            const SizedBox(height: 24),
            _buildPasswordInput(),
            const SizedBox(height: 24),
            _buildCodeInput(),
            const SizedBox(height: 8),
            _buildSmsHelpLink(),
            const SizedBox(height: 24),
            _buildActionButtons(),
            const SizedBox(height: 40),
            _buildPrivacyAgreement(),
          ],
        ),
      ),
    ),
  );
}

5.手机号输入框

Widget _buildPhoneInput() {
  return Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
      Row(
        children: [
          Icon(Icons.phone_outlined, color: Colors.grey[600], size: 20),
          const SizedBox(width: 8),
          Text(
            '手机号',
            style: TextStyle(
              fontSize: 16,
              color: Colors.grey[700],
              fontWeight: FontWeight.w500,
            ),
          ),
        ],
      ),
      const SizedBox(height: 12),
      TextField(
        controller: _phoneController,
        keyboardType: TextInputType.phone,
        decoration: InputDecoration(
          hintText: '请输入手机号',
          hintStyle: TextStyle(color: Colors.grey[400]),
          filled: true,
          fillColor: const Color(0xFFF9FAFB),
          border: OutlineInputBorder(
            borderRadius: BorderRadius.circular(8),
            borderSide: BorderSide.none,
          ),
          contentPadding: const EdgeInsets.symmetric(
            horizontal: 16,
            vertical: 14,
          ),
        ),
      ),
    ],
  );
}

代码解释

1.与登录页面保持一致的设计风格

2.使用数字键盘类型TextInputType.phone

3.浅灰色背景

6.密码输入框

Widget _buildPasswordInput() {
  return Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
      Row(
        children: [
          Icon(Icons.lock_outline, color: Colors.grey[600], size: 20),
          const SizedBox(width: 8),
          Text(
            '密码',
            style: TextStyle(
              fontSize: 16,
              color: Colors.grey[700],
              fontWeight: FontWeight.w500,
            ),
          ),
        ],
      ),
      const SizedBox(height: 12),
      TextField(
        controller: _passwordController,
        obscureText: _obscurePassword,
        decoration: InputDecoration(
          hintText: '请输入密码',
          hintStyle: TextStyle(color: Colors.grey[400]),
          filled: true,
          fillColor: const Color(0xFFF9FAFB),
          border: OutlineInputBorder(
            borderRadius: BorderRadius.circular(8),
            borderSide: BorderSide.none,
          ),
          contentPadding: const EdgeInsets.symmetric(
            horizontal: 16,
            vertical: 14,
          ),
          suffixIcon: IconButton(
            icon: Icon(
              _obscurePassword ? Icons.visibility_off : Icons.visibility,
              color: Colors.grey[400],
              size: 20,
            ),
            onPressed: () {
              setState(() {
                _obscurePassword = !_obscurePassword;
              });
            },
          ),
        ),
      ),
    ],
  );
}

7.验证码输入框

Widget _buildCodeInput() {
  return Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
      Row(
        children: [
          Icon(Icons.shield_outlined, color: Colors.grey[600], size: 20),
          const SizedBox(width: 8),
          Text(
            '验证码',
            style: TextStyle(
              fontSize: 16,
              color: Colors.grey[700],
              fontWeight: FontWeight.w500,
            ),
          ),
        ],
      ),
      const SizedBox(height: 12),
      Row(
        children: [
          // 验证码输入框
          Expanded(
            child: TextField(
              controller: _codeController,
              keyboardType: TextInputType.number,
              decoration: InputDecoration(
                hintText: '请输入验证码',
                hintStyle: TextStyle(color: Colors.grey[400]),
                filled: true,
                fillColor: const Color(0xFFF9FAFB),
                border: OutlineInputBorder(
                  borderRadius: BorderRadius.circular(8),
                  borderSide: BorderSide.none,
                ),
                contentPadding: const EdgeInsets.symmetric(
                  horizontal: 16,
                  vertical: 14,
                ),
              ),
            ),
          ),
          const SizedBox(width: 12),
          // 获取验证码按钮
          ElevatedButton(
            onPressed: _countdown > 0 ? null : _sendVerificationCode,
            style: ElevatedButton.styleFrom(
              backgroundColor: const Color(0xFF4CAF50),
              foregroundColor: Colors.white,
              disabledBackgroundColor: Colors.grey[300],
              disabledForegroundColor: Colors.grey[600],
              padding: const EdgeInsets.symmetric(
                horizontal: 20,
                vertical: 14,
              ),
              shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(8),
              ),
              elevation: 0,
            ),
            child: Text(
              _countdown > 0 ? '${_countdown}s' : '获取验证码',
              style: const TextStyle(
                fontSize: 14,
                fontWeight: FontWeight.w500,
              ),
            ),
          ),
        ],
      ),
    ],
  );
}

代码解释一下

输入框和按钮并排布局

按钮根据倒计时状态动态显示文字

倒计时期间按钮禁用(onPressed: null)

禁用状态使用灰色

8.短信帮助功能

这个我要额外说一下 由于本人是个人开发者 所以懂得都懂 只能借鉴第3方 这个时候 这个功能我觉得是非常重要的

Align(
  alignment: Alignment.centerRight,
  child: TextButton(
    onPressed: _showSmsHelpDialog,
    child: const Text(
      '短信遇到问题?',
      style: TextStyle(
        color: Color(0xFF9CA3AF),
        fontSize: 13,
        decoration: TextDecoration.underline,
        decorationColor: Color(0xFF9CA3AF),
      ),
    ),
  ),
)

9.返回登录和立即注册功能

Row(
  children: [
    // 返回登录按钮
    Expanded(
      child: OutlinedButton(
        onPressed: () {
          Navigator.pop(context);
        },
        style: OutlinedButton.styleFrom(
          padding: const EdgeInsets.symmetric(vertical: 16),
          side: const BorderSide(color: Color(0xFFE5E7EB)),
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(8),
          ),
        ),
        child: const Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Icon(Icons.arrow_back, size: 18, color: Color(0xFF6B7280)),
            SizedBox(width: 8),
            Text(
              '返回登录',
              style: TextStyle(
                fontSize: 15,
                color: Color(0xFF6B7280),
                fontWeight: FontWeight.w500,
              ),
            ),
          ],
        ),
      ),
    ),
    const SizedBox(width: 12),
    // 立即注册按钮
    Expanded(
      flex: 2,
      child: ElevatedButton(
        onPressed: _handleRegister,
        style: ElevatedButton.styleFrom(
          backgroundColor: const Color(0xFF4CAF50),
          foregroundColor: Colors.white,
          padding: const EdgeInsets.symmetric(vertical: 16),
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(8),
          ),
          elevation: 0,
        ),
        child: const Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Icon(Icons.person_add, size: 18),
            SizedBox(width: 8),
            Text(
              '立即注册',
              style: TextStyle(
                fontSize: 15,
                fontWeight: FontWeight.w600,
              ),
            ),
          ],
        ),
      ),
    ),
  ],
)

10.校验是否为空

void _handleRegister() async {

// 验证手机号

if (_phoneController.text.isEmpty) {

_showMessage('请输入手机号');

return;

}

// 验证密码

if (_passwordController.text.isEmpty) {

_showMessage('请输入密码');

return;

}

// 验证验证码

if (_codeController.text.isEmpty) {

_showMessage('请输入验证码');

return;

}

// 验证隐私政策

if (!_agreedToPrivacy) {

_showMessage('请先阅读并同意隐私政策');

return;

}

}

10.调用注册的API

final result = await UserApi.register(

phone: _phoneController.text,

password: _passwordController.text,

code: _codeController.text,

);

11.注册成功之后的处理逻辑

if (result != null && result['success'] == true) {

// 注册成功,跳转到主页面,其实我觉得调回登录页蛮好的 ,后续改改吧

if (mounted) {

Navigator.pushAndRemoveUntil(

context,

MaterialPageRoute(builder: (context) => const MainPage()),

(route) => false, 

);

}

} else {

// 注册失败,显示错误信息

final message = result?['message'] ?? '注册失败,请重试';

_showMessage(message);

}

12.颜色推荐

颜色用途 颜色值 说明
主题色 0xFF4CAF50 按钮,复选框
主文本 0xFF1F2937 标题文字
次要文本 Colors.grey[700]
提示文本 Colors.grey[400] 输入框占位符
帮助文本 0xFF9CA3AF
内容文本 0xFF4B5563 对话框内容
输入框背景 0xFFF9FAFB 浅灰色背景
边框颜色 0xFFE5E7EB 按钮边框
禁用背景 Colors.grey[300] 禁用按钮背景

13.最后

欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐