flutter 并不完美的登录完美验证功能

news2024/11/24 21:06:44

flutter 并不完美的登录完美验证功能

  • 前言
  • 一、文本输入功能
  • 二、验证提示功能
  • 三、业务部分
  • 总结


前言

在一个APP 中,登录页面做为门户,很多时候,我们都需要写一个完善的登录验证页面,本篇文章将记录如何去封装一个并不算完美的登录验证页面。


一、文本输入功能

本篇文章将使用Form 表单的形式,来完成输入文本的基本布局,关于Form 表单等组件的详细说明,请看分栏中的flutter 入门篇。

本篇文章,其实我只是想用Form 表单的验证功能,但是在实际使用中,我发现Form 表单的验证提示信息部分,并不是特别的灵活,会有一定的限制,so:如果你有想法,可以在后续继续完善,也可以自行替换,我这里只是用于记录。

下面我们先来看写一个文本输入框

Container(
  decoration: BoxDecoration(
    border: Border.all(color: Colors.blue, width: 1),
    borderRadius: BorderRadius.all(Radius.circular(6.r)),
  ),
  child: TextFormField(
    autofocus: model.userNode,
    controller: model.userController,
    onEditingComplete: model.scopeNode.nextFocus,
    decoration: const InputDecoration(
      hintText: "请输入用户名",
      icon: Icon(Icons.person),
      border: InputBorder.none,
    ),
    onChanged: (value){
      model.userValidation(value);
    },
  ),
)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-py8ps9Su-1672300185062)(/Users/tiger/Library/Application Support/typora-user-images/image-20221229152838102.png)]

这里我选用自定义样式的方式,进行一个简单的样式定义

二、验证提示功能

文本输入框有了,接下来我们再来写一个错误提示的组件

Offstage(
  offstage: model.userOffstage,
  child: Container(
    padding: const EdgeInsets.only(top: 5),
    alignment: Alignment.centerRight,
    child: const Text(
      "用户名不能为空",
      style: TextStyle(
        color: Colors.red,
      ),
    ),
  ),
),

这里我使用了一个新的组件,Offstage 组件,这个组件主要的作用就是展示和隐藏其它的组件,个人认为,这个组件在一些特定的情况下,还是蛮好用的,有兴趣的可以去了解一下。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UwMpe5Wc-1672300185064)(/Users/tiger/Library/Application Support/typora-user-images/image-20221229153243240.png)]

其实到这里,我们还需要一个体检login 按钮,就不介绍了,自己根据实际项目需要,去自定义一个就可以了。

先来看一下实际运行效果图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E5nbKeoW-1672300185065)(/Users/tiger/Library/Application Support/typora-user-images/image-20221229153517086.png)]

三、业务部分

个人写项目,比较喜欢前后分离,这样不管在后期的项目维护,版本升级,或者日常开发中,都是比较简单明了的,上面UI 部分已经完成,接下来我们一起来看一下业务逻辑相关部分代码

  1. 关于文本输入框的焦点部分,我们需要定义所有文本输入框的焦点状态

    bool userNode = true;
    
  2. 密码文本输入框,我们需要有展示和隐藏明文的功能

bool obscureText = true;
  1. 关于报错信息的展示控制 Offstage 组件的控制,那么我们应该相应的定义一个控制属性
bool userOffstage = true;
  1. 现在所有的属性都已经定义完成了,现在我们需要对用户输入的信息进行检验
// 验证用户名
userValidation(String input) {
  userOffstage = true;
  if (!TextUtils.validationInput(input)) {
    userOffstage = false;
  }

  notifyListeners();
}

我这里只是一个简单的为空验证检测方法,可根据实际项目需求,来完善自己的验证方法,validationInput 字符检验方法,在flutter 进阶专栏有记录,有兴趣的朋友可以去查看。

文章写到这里,其实我们的整个功能,就已经写完了,内容比较简单,下面来看一下完整的代码

UI 部分

static Widget bodyWidget(LoginViewModel model) {
  return Container(
    padding: EdgeInsets.symmetric(horizontal: 20.w),
    child: Column(
      children: [
        const SizedBox(
          height: 150,
        ),
        textField(model),
        const SizedBox(
          height: 50,
        ),
        submitBtn(model),
      ],
    ),
  );
}

static Widget textField(LoginViewModel model) {
  return Form(
    key: model.formGlobalKey,
    autovalidateMode: AutovalidateMode.onUserInteraction,
    child: FocusScope(
      node: model.scopeNode,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Container(
            decoration: BoxDecoration(
              border: Border.all(color: Colors.blue, width: 1),
              borderRadius: BorderRadius.all(Radius.circular(6.r)),
            ),
            child: TextFormField(
              autofocus: model.userNode,
              controller: model.userController,
              onEditingComplete: model.scopeNode.nextFocus,
              decoration: const InputDecoration(
                hintText: "请输入用户名",
                icon: Icon(Icons.person),
                border: InputBorder.none,
              ),
              onChanged: (value){
                model.userValidation(value);
              },
            ),
          ),
          Offstage(
            offstage: model.userOffstage,
            child: Container(
              padding: const EdgeInsets.only(top: 5),
              alignment: Alignment.centerRight,
              child: const Text(
                "用户名不能为空",
                style: TextStyle(
                  color: Colors.red,
                ),
              ),
            ),
          ),
          const SizedBox(
            height: 10,
          ),
          Container(
            decoration: BoxDecoration(
              border: Border.all(color: Colors.blue, width: 1),
              borderRadius: BorderRadius.all(Radius.circular(6.r)),
            ),
            child: TextFormField(
              autofocus: model.passNode,
              controller: model.passController,
              obscureText: model.obscureText,
              onEditingComplete: model.scopeNode.nextFocus,
              decoration: InputDecoration(
                hintText: "请输入用户名",
                icon: const Icon(Icons.person),
                border: InputBorder.none,
                suffixIcon: IconButton(
                  onPressed: () {
                    model.obscureText = !model.obscureText;
                    model.notifyListeners();
                  },
                  icon: Icon(model.obscureText
                      ? Icons.remove_red_eye_outlined
                      : Icons.remove_red_eye),
                ),
              ),
              onChanged: (value){
                model.passValidation(value);
              },
            ),
          ),
          Offstage(
            offstage: model.passOffstage,
            child: Container(
              padding: const EdgeInsets.only(top: 5),
              alignment: Alignment.centerRight,
              child: const Text(
                "密码不能为空",
                style: TextStyle(
                  color: Colors.red,
                ),
              ),
            ),
          ),
        ],
      ),
    ),
  );
}

static Widget submitBtn(LoginViewModel model) {
  return InkWell(
    onTap: () {
      model.login();
    },
    child: Container(
      height: 50,
      alignment: Alignment.center,
      decoration: BoxDecoration(
        color: Colors.blue,
        borderRadius: BorderRadius.all(
          Radius.circular(8.r),
        ),
      ),
      child: const Text(
        "login",
        style: TextStyle(
          color: Colors.white,
          fontWeight: FontWeight.w800,
        ),
      ),
    ),
  );
}

业务逻辑部分

// Form 表单唯一的Key
GlobalKey formGlobalKey = GlobalKey();
TextEditingController userController =
    TextEditingController(text: "13042824000");
TextEditingController passController =
    TextEditingController(text: "12345678");
FocusScopeNode scopeNode = FocusScopeNode();

// 用户名和密码的焦点
bool userNode = true;
bool passNode = false;

// 密码输入框,是否展示明文
bool obscureText = true;

// 显示隐藏报错信息
bool userOffstage = true;
bool passOffstage = true;

// 验证用户名
userValidation(String input) {
  userOffstage = true;
  if (!TextUtils.validationInput(input)) {
    userOffstage = false;
  }

  notifyListeners();
}

// 验证密码
passValidation(String input) {
  passOffstage = true;
  if (!TextUtils.validationInput(input)) {
    passOffstage = false;
  }

  notifyListeners();
}

login() {
  // 获取当前用户名和密码的状态
  if (!userOffstage && !passOffstage) {
    ToastUtils.showError("账号或密码错误");
    return;
  }

  // 用户登录基本信息存储
  PreferencesUtils.setString("user", userController.text);
  PreferencesUtils.setString("pass", passController.text);

  // 登录成功,返回之前页
  back();
}


总结

本篇文章内容较少,代码也比较少,如果对你有帮忙,麻烦点个赞,或者你想看什么,可以在下面留言,感谢你的支持。

最近我在参与博客之星的评选活动,如果我的文章对你有帮助,请点击这里 给予五星支持一下,谢谢。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/126428.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

BurpSuite抓取App包,详细教程

BurpSuite抓取App包,详细教程1.工具准备2.手动代理模拟器3.修改BurpSuite代理4.测试最近有很多粉丝小伙伴反映自己不会使用BurpSuite抓取手机App的流量包,其实很简单,和Web基本是如出一辙的 1.工具准备 夜神模拟器 BurpSuite请自行准备环境…

CISP-DSG证书有效期多久?是否需要续证?

CISP-DSG证书有效期为3年。有效期结束后需向中国信息安全测评中心授权机构进行续证维持,并缴纳证书维持费。如超期半年以上需多交一年年金,以此累计。建议大家在证书到期前三个月提交材料进行续证。那么CISP-DSG续证流程是什么呢?以下是小编整…

Android 教程

Android 是一个开源的,基于 Linux 的移动设备操作系统,主要使用于移动设备,如智能手机和平板电脑。Android 是由谷歌及其他公司带领的开放手机联盟开发的。 本教程将教会你基本的 Android 编程,以及学习一些 Android 应用程序开发…

【Python】sklearn之AP聚类AffinityPropagation

文章目录基本原理sklearn中的实现基本原理 AffinityPropagation按照字面意思就是亲和力传播,可见这个算法的关键就是亲和力与传播。 说到传播,无外乎两件事,第一件事,传的是什么,暂且先不用管,因为名字里…

WORD: 如何在一个word里文档里创建多个目录?

如何在一个word里文档里创建多个目录? 1 目录的创建 引用/目标/自动目录 (同时文章本身需要设置层级标题正文等) 一般不选手动目录,没试过狠麻烦吧2 如何设置2个目录呢? 直接在新的地方插入一个目录,选择…

OpenGL教程一,窗体和图形的渲染(包含OpenGL、GLFW、GLAD)

运行环境:Linux 、C 本教程仅个人学习总结第一个hello world,渲染一个窗体渲染一个矩形本教程仅个人学习总结 一切参考资源:都在官网。 1、安装glfw 首先下载glfw : 点击这里 1、下载 2、解压 3、mkdir build && cd build 4、cmake …

学习poi导出excel之XSSFWorkbook

1 基本介绍 POI提供了HSSF、XSSF以及SXSSF三种方式操作Excel。 HSSF:Excel97-2003版本,扩展名为.xls。一个sheet最大行数65536,最大列数256。 XSSF:Excel2007版本开始,扩展名为.xlsx。一个sheet最大行数1048576&…

电脑桌面主题(28)和动态视频壁纸(31)合集(收藏)

最近就是突然被身边朋友的电脑壁纸给吸引到了,在这之前的我一直遵循着 “大道至简” 的原则,一张Windows原生态静态壁纸走天下,但是作为一个00后我还是 “破戒” 了,其实我认为特别像程序员之类的有一张自己满意的桌面壁纸是非常重…

Mybatis-Plus分页与条件查询

目录 标准分页功能制作 条件查询 条件查询-null值处理 标准分页功能制作 1:设置分页拦截器作为Spring管理的bean Configuration public class MpConfig {Beanpublic MybatisPlusInterceptor mpInterceptor(){//1.定义MP拦截器MybatisPlusInterceptor mpIntercept…

Python中使用的流行数据科学库

Python中使用的流行数据科学库 数据科学是用于采购、组织、打包和以可理解的格式呈现数据的程序和方法。在不同的领域可能有不同种类的数据,这些数据可能是结构化的,也可能是非结构化的。 为什么Python在人们开始他们的编码之旅时如此受欢迎&#xff1…

删除数组中符合指定条件的元素

不符合指定条件&#xff0c;可能是指定数组array中的某一项不符合某一值的要求&#xff1b;或者是拿另一个数组arr对比&#xff0c;要求array只留下复合arr中的值或者删除掉复合arr中的值。 1.不符合某一值的要求 <!DOCTYPE html> <html lang"en"> <…

一篇文章轻松掌握java图实现

图的基本概念&#xff1a;这里就不予介绍了&#xff0c;这里主要是讲图的代码实现 荔枝目录&#xff1a;1.图的存储结构1.1邻接矩阵1.2邻接表2.图的遍历2.1广度优先2.2深度优先3.最小生成树3.1Kruskal算法&#xff08;全局&#xff09;3.2Prim算法&#xff08;局部&#xff09;…

[UE][UE5]在UE中画一个线框球,网格连接画球,高阶画球并操控

[UE][UE5]在UE中画一个线框球&#xff0c;网格连接画球&#xff0c;高阶画球并操控1.材质法2.绘制调试球体3.网格连接4.高阶画球并操控1.材质法 缺点&#xff1a;是实体的&#xff0c;只能欺骗视觉&#xff0c;实际还是一个实体体积球&#xff0c;往里放东西显示不出来放进去的…

Python中ArcPy基于矢量要素批量将栅格影像切割为多个小部分

本文介绍基于Python中ArcPy模块&#xff0c;基于具有多个面要素的要素类&#xff0c;批量分割大量栅格图像的方法。 首先明确一下我们的需求。现在需要基于一个面要素类&#xff0c;对一个栅格遥感影像加以分割&#xff1b;如下图所示。这个面要素类中有3个部分&#xff0c;我们…

MMdetection框架速成系列 第02部分:整体算法流程+模型搭建流程+detection训练与测试核心组件+训练部分与测试部分的核心算法

MMdetection框架速成系列 第02部分1 MMDetection是什么1.1 模型分类2. 整体算法流程3 detection训练核心组件3.1 Backbone3.2 Neck3.3 Head3.4 Enhance3.5 BBox Assigner3.9 BBox Sampler3.10 BBox Encoder3.11 Loss3.12 Training tricks4 detection测试核心组件4.1 BBox Decod…

python源码打包exe、exe反编译

一、python3打包为exe文件 这里有个hello.py文件 step1&#xff1a;安装pyinstaller包 pip install pyinstaller step2&#xff1a;在cmd中进入hello.py文件所在路径。可以直接在hello.py文件路径下直接进入cmd step3&#xff1a;打包生成exe文件&#xff0c;使用如下命令&…

Linux网络协议之IP协议(网络层)

Linux网络协议之IP协议(网络层) 文章目录Linux网络协议之IP协议(网络层)1.IP协议基本概念2.IPV4协议格式3.分片与组装4.IP网段划分4.1 IP地址组成4.2 IP地址分类4.3 特殊的IP地址4.4 IP地址的数量限制4.5 私网IP地址与公网IP地址5.对路由的了解1.IP协议基本概念 IP协议全称为“…

第四章 vi和vim 编辑器-[实操篇]

一&#xff1a;vi 和 vim 的基本介绍 所有的 Linux 系统都会内建vi文本编辑器。 Vim 具有程序编辑的能力&#xff0c;可以看做是 Vi的增强版本&#xff0c;可以主动的以字体颜色辨别语法的正确性&#xff0c;方便程序设计。代码补完&#xff0c;编译及错误跳转等方便编程的功…

Linux安装【入门学习适用】

Linux安装安装1、安装VMware激活码&#xff1a;ZF3R0-FHED2-M80TY-8QYGC-NPKYF2、安装CentOS3、FinalShell安装4、FinalShell的使用安装 1、安装VMware VMware-workstation-full-16.2.4无脑下一步即可 激活码&#xff1a;ZF3R0-FHED2-M80TY-8QYGC-NPKYF 2、安装CentOS 1、…

TensorFlow笔记之多元线性回归

文章目录前言一、数据处理二、TensorFlow1.x1.定义模型2.训练模型3.结果可视化4.模型预测5.TensorBoard可视化三、TensorFlow2.x1.定义模型2.训练模型3.结果可视化4.模型预测总结前言 记录使用TensorFlow1.x和TensorFlow2.x完成多元线性回归的过程。 一、数据处理 在此使用波…