Flutter Form表单雏形

126 阅读1分钟

UI表现

IMG_1229.HEIC

代码

import 'dart:async';

import 'package:flutter/material.dart';

// TODO 滑块验证码
// TODO form onWillPop
// TODO form样式

/// 建议,onSaved , 数据获取
/// 或者每项都加上 TextEditController

class LoginPage extends StatelessWidget {
  const LoginPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("登录"),
      ),
      body: Login(),
    );
  }
}

/// 登录界面
///
class Login extends StatefulWidget {
  const Login({super.key});

  @override
  State<Login> createState() => _LoginState();
}

class _LoginState extends State<Login> {
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();

  final Map<String, dynamic> formData = {};

  @override
  void initState() {
    super.initState();
  }

  @override
  void dispose() {
    super.dispose();
  }

  void submitHandle() {
    if (!_formKey.currentState!.validate()) {
      print("验证失败");
    }

    _formKey.currentState!.save();

    print('formData ::: > $formData');
  }

  void formChangeHandle() {}

  bool showObscureText = true;
  // 切换密码的
  void togglePassword() {
    setState(() {
      showObscureText = !showObscureText;
    });
  }

  Widget passwordEyeIcon() {
    Icon eyeIcon = !showObscureText
        ? Icon(Icons.remove_red_eye_outlined)
        : Icon(Icons.visibility_off);
    return GestureDetector(onTap: togglePassword, child: eyeIcon);
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      alignment: Alignment.center,
      child: Form(
        key: _formKey,
        onChanged: formChangeHandle,
        child: Column(
          children: [
            Container(
              padding: const EdgeInsets.all(20.0),
              child: TextFormField(
                onSaved: (newValue) => formData["phone"] = newValue,
                key: ValueKey('phone'),
                keyboardType: TextInputType.phone, // 键盘类型
                validator: (String? value) {
                  if (value == null || value.isEmpty) {
                    return 'Please enter some text';
                  }
                  return null;
                },
                decoration: InputDecoration(
                  hintText: "请输入手机号",
                  counterText: '',
                  border: OutlineInputBorder(),
                ),
              ),
            ),
            Container(
              padding: const EdgeInsets.all(20.0),
              child: TextFormField(
                key: ValueKey("password"),
                onSaved: (newValue) => formData["password"] = newValue,
                obscureText: showObscureText,
                keyboardType: TextInputType.visiblePassword,
                validator: (String? value) {
                  if (value == null || value.isEmpty) {
                    return 'Please enter some text';
                  }
                  return null;
                },
                decoration: InputDecoration(
                  suffixIcon: passwordEyeIcon(),
                  hintText: "请输入密码",
                  counterText: '',
                  border: OutlineInputBorder(),
                ),
              ),
            ),
            Container(
              padding: const EdgeInsets.all(20.0),
              child: VerifyCodeField(),
            ),
            ElevatedButton(
              onPressed: submitHandle,
              child: Text("submit"),
            ),
          ],
        ),
      ),
    );
  }

  Widget VerifyCodeField() {
    return Row(
      children: [
        Expanded(
          child: TextFormField(
            key: ValueKey("verifyCode"),
            onSaved: (newValue) => formData['verifyCode'] = newValue,
            keyboardType: TextInputType.number,
            validator: (String? value) {
              if (value == null || value.isEmpty) {
                return 'Please enter some text';
              }
              return null;
            },
            decoration: InputDecoration(
              hintText: "请输入验证码",
              counterText: '',
              border: OutlineInputBorder(),
            ),
          ),
        ),
        Padding(
          padding: const EdgeInsets.only(left: 20.0),
          child: WaitSecondButton(
            onPressed: () {},
          ),
        )
      ],
    );
  }
}

/// 验证码 读秒的button
class WaitSecondButton extends StatefulWidget {
  const WaitSecondButton({super.key, required this.onPressed});
  final VoidCallback onPressed;

  @override
  State<WaitSecondButton> createState() => _WaitSecondButtonState();
}

class _WaitSecondButtonState extends State<WaitSecondButton> {
  final int defaultSecond = 3;
  final String normalText = '验证码';

  Timer? _timer;

  late ValueNotifier<int> waitSecond = ValueNotifier(defaultSecond);

  @override
  void initState() {
    super.initState();
  }

  @override
  void dispose() {
    _timer?.cancel();
    super.dispose();
  }

  bool isWait = false;

  // 发送验证码
  void sendVerfyCode() {
    if (isWait) {
      return;
    }
    print("发送验证码");
    setState(() {
      isWait = true;
      startPeriodic();
      widget.onPressed();
    });
  }

  // 开始读秒
  void startPeriodic() {
    _timer = Timer.periodic(Duration(seconds: 1), (timer) {
      waitSecond.value--;
      if (waitSecond.value <= 0) {
        stopPeriodic();
      }
    });
  }

  // 结束独苗
  void stopPeriodic() {
    _timer?.cancel();
    setState(() {
      isWait = false;
      waitSecond.value = defaultSecond;
    });
  }

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: sendVerfyCode,
      child: isWait
          ? ValueListenableBuilder(
              valueListenable: waitSecond,
              builder: (BuildContext context, int value, Widget? widget) {
                return Text('$value秒');
              })
          : Text(normalText),
    );
  }
}