iOS SwiftUI 数据表单Form从菜鸟到高手的四种实现方案

网络工
• 阅读 5110
采集数据、处理数据、展示数据是一个程序的最基本功能。今天我们来学习一下如何使用SwiftUI的Form来采集数据。

本期我们以最基础的用户注册界面为例子,向大家介绍一下数据收集的四种不同水平的实现方式。

初学者方式

相信长期看我专栏的朋友,应该可以快速搭建起下面的界面。非常简单就是VStack、HStack、TextField等组件的简单组合而已。

iOS SwiftUI 数据表单Form从菜鸟到高手的四种实现方案

import SwiftUI

struct SignUpForm0: View {
    @State var username = ""
    @State var email = ""
    
    var body: some View {
        NavigationView{
            Form {
                Text("初学者做的用户注册界面").font(.headline)
                HStack {
                    Image(systemName: "person.circle.fill")
                    TextField("Username", text: $username)
                }
                HStack {
                    Image(systemName: "envelope.circle.fill")
                    TextField("Email", text: $email)
                }
                Button(
                    action: { print("here") },
                    label: { Text("提交") }
                )
            }.navigationBarTitle(Text("用户注册界面"))
        }
    }
}

入门级方式

入门级的界面和初学者的完全一样,但是在构建界面时却开始使用模块化思想了。
初学者阶段,我们使用了两次相同的HStack + Image + TextField组合,但这并不一定是问题,因为我们对两个文本字段的配置都大不相同。但假设我们想在其他地方也复用这些代码,该如何操作呢。其实非常简单,我们将这些代码封装成一个独立的组件即可。

为了实现这个想法,我们先创建一个struct视图,然后将Image和Text都封装进入,最后通过@Bingding来进行数值的传递。

struct IconPrefixedTextField: View {
    var iconName: String
    var title: String
    @Binding var text: String
    
    var body: some View {
        HStack {
            Image(systemName: iconName)
            TextField(title, text: $text)
        }
    }
}

在主界面中,使用新创建的组件进行数据收集。怎么样代码变得更简洁了吧。

import SwiftUI

struct SignUpForm1: View {
    @State var username = ""
    @State var email = ""
    
    var body: some View {
        NavigationView{
            Form {
                Text("入门后做的用户注册界面").font(.headline)
                IconPrefixedTextField(
                    iconName: "person.circle.fill",
                    title: "Username",
                    text: $username
                )
                IconPrefixedTextField(
                    iconName: "envelope.circle.fill",
                    title: "Email",
                    text: $email
                )
                Button(
                    action: { print("here") },
                    label: { Text("提交") }
                )
            }.navigationBarTitle(Text("用户注册界面"))
        }
    }
}

中级水平

刚才,我们看过初学者快速的构建界面,入门级的采用模块化编程思想,那么中级选手会如何实现呢。
中级选手会告诉我们上面两种实现方式都不是SwiftUI都佳实现模式。尽管上述更改将使我们能够在SignUpForm之外重用我们新的IconPrefixedTextField类型,但是否最终改善了我们的原始代码却值得怀疑。毕竟,我们并没有真正简化注册表单的实现过程。实际上,调用方式上看起来比以前还复杂了很多。

我们还是从SwiftUI自己的API设计中汲取一些灵感吧,看看如果将文本视图配置代码改为View扩展来实现的话,会是什么样子。

extension View {
    func prefixedWithIcon(named name: String) -> some View {
        HStack {
            Image(systemName: name)
            self
        }
    }
}

上面代码非常简单,我们就是对View视图进行一下拓展,丰富一下View组合。extension做好后,我们就可以用SwiftUI的链式调用方法来进行界面配置了。

TextField("Username", text: $username)
                    .prefixedWithIcon(named: "person.circle.fill")

完成上述操作后,我们现在可以将任何SF Symbols图标直接添加到SwiftUI中的TextField视图或其他任何视图中.

下面我们来看看项目的完整代码

import SwiftUI

struct SignUpForm2: View {
    @State var username = ""
    @State var email = ""
    
    var body: some View {
        NavigationView{
            Form {
                Text("中级水平做的用户注册界面").font(.headline)
                
                TextField("Username", text: $username)
                    .prefixedWithIcon(named: "person.circle.fill")
                TextField("Email", text: $email)
                    .prefixedWithIcon(named: "envelope.circle.fill")
                
                Button(
                    action: { print("here") },
                    label: { Text("提交") }
                )
            }.navigationBarTitle(Text("用户注册界面"))
        }
    }
}

中高级水平

中级水平已经对界面进行SwiftUI式的改造,中高级选手就开始将注意力集中在业务逻辑方面了。例如,对输入内容验证方面。我们先看看下面的动图。

iOS SwiftUI 数据表单Form从菜鸟到高手的四种实现方案

假如我们想要求用户的名称必须大于5位,邮件必须是邮件格式,并且只有满足上面两个条件后才会出现提交按钮,这类稍稍复杂的效果该如何实现呢?

实现方式有很多种,但是最简洁、最灵活、最高效的实现方式是什么呢?

答案当然是SwiftUI式的编码方式。下面我就带领大家来实现一下吧!

第一步 编写个验证邮件的函数

我个人比较喜欢用NSPredicate来实现

func isValidEmail(_ email: String) -> Bool {
    let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"

    let emailPred = NSPredicate(format:"SELF MATCHES %@", emailRegEx)
    return emailPred.evaluate(with: email)
}

第二步 创建 ViewModifier 当用户满足条件就让边框变为绿色

struct Validation<Value>: ViewModifier {
    var value: Value
    var validator: (Value) -> Bool
    
    func body(content: Content) -> some View {
        // Here we use Group to perform type erasure, to give our
        // method a single return type, as applying the 'border'
        // modifier causes a different type to be returned:
        Group {
            if validator(value) {
                content.border(Color.green)
            } else {
                content
            }
        }
    }
}

主页面

struct SignUpForm3: View {
    @State var username = ""
    @State var email = ""
    @State var uFlag = false
    @State var eFlag = false
    
    
    var body: some View {
        NavigationView{
            Form {
                Text("中高级做的用户注册界面").font(.headline)
                TextField("Username", text: $username)
                    .modifier(Validation(value: username) { name in
                        self.uFlag = name.count > 4
                        return self.uFlag
                        
                    })
                    .prefixedWithIcon(named: "person.circle.fill")
                
                TextField("Email", text: $email)
                    .modifier(Validation(value: email) { name in
                        self.eFlag = isValidEmail(name)
                        return self.eFlag
                        
                    })
                    .prefixedWithIcon(named: "envelope.circle.fill")
                
                if (self.uFlag && self.eFlag){
                Button(
                    action: {print("here")},
                    label: { Text("提交") }
                )
                }
            }.navigationBarTitle(Text("用户注册界面"))
        }
    }
}

总结

本文带着大家领略了从菜鸟到高手不同层次选手完成相同任务时的不同思考模式:

  • 初学者模式

简单使用HStack + Image + TextField组合,快速实现需求。得益于SwiftUI强大功能,界面可以达到苹果的设计水准

  • 入门级水平

对代码整洁度和代码复用提出了要求,开始效仿SwiftUI对代码进行模块化改造。

  • 中级水平

开始不满足于简单模块化改造,开始从SwiftUI的API设计中汲取灵感,尝试采用链式编码。

  • 中高级水平

中高级选手开始将注意力集中在业务逻辑方面了。

  • 顶级高手呢

很遗憾,俺的水平有限只能介绍到上面的水平了。


如果需要项目完整源码,可以加我QQ。

QQ:3365059189
SwiftUI技术交流QQ群:518696470

https://www.jianshu.com/c/7b3...

点赞
收藏
评论区
推荐文章
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Firefox数据抓包分享
啥是POST请求呢?我们在做一些信息提交的时候比如注册,登录这时候我们做的就是POST请求,POST的参数不会直接放在URL上,会以Form表单的形式将数据提交给服务器。我们来登录一下ip.16yun.cn:817还有就是请
Wesley13 Wesley13
4年前
STM32基础定时器详解
定时器最基本的功能就是定时处理事情。比如定时发送USART数据、定时采集AD数据、定时检测IO口电位、还可以通过IO口输出波形等。可以实现非常丰富的功能。定时器是一个很强大的外设,不同行业使用的方式不同,知识面很广。01、定时器介绍首先我们可以在STM32F207数据手册找到定制器的资源,从下图可以看到STM32F207一共10个通
Irene181 Irene181
4年前
肝了三天,万字长文教你玩转 tcpdump,从此抓包不用愁
系列导读本文是【网络知识扫盲】专栏的第三篇。今天要给大家介绍的一个Unix下的一个网络数据采集分析工具\Tcpdump,也就是我们常说的抓包工具。与它功能类似的工具有wireshark,不同的是,wireshark有图形化界面,而tcpdump则只有命令行。由于我本人更习惯使用命令行的方式进行抓包,因此今天先跳过
Karen110 Karen110
4年前
一篇文章带你了解Django Form组件(入门篇)
前言Hey,大家好呀,我是码农,星期八。本次咱们来get一个新技能,Form组件。Form组件主要用于验证表单数据。为什么需要Form组件注:Form组件,只适用于,前后端未分离的项目中,主要用于验证表单数据,所以,关键字是表单!!!比如像哔哩哔哩的注册界面。我点击注册,它不仅仅可以知道我的注册昵称是否存在,密码是否小于6位,手机号格式错误。还会把错误信
Wesley13 Wesley13
4年前
IP地址定位技术中基础数据采集怎么做?
IP地理位置定位技术,包含基础数据采集、硬件系统搭建、应用场景划分和定位系统研发四项关键技术。基础数据采集为IP地理位置定位技术的研究提供基础数据支撑,是IP地址定位的基础性工作和关键技术。首先,按照不同的数据采集规则,针对不同数据源的数据格式,研究并实现一套自动化的智能化的数据采集技术;其次,对采集到的数据进行筛选、清洗和挖掘,形成基础数据库,为系统提
Wesley13 Wesley13
4年前
UAVStack功能上新:新增JVM监控分析工具
UAVStack推出的JVM监控分析工具提供基于页面的展现方式,以图形化的方式展示采集到的监控数据;同时提供JVM基本参数获取、内存dump、线程分析、内存分配采样和热点方法分析等功能。引言作为AllInOne的智能化服务技术栈,UAVStack提供了非常全面的监控数据采样功能,同时支持数据监控与预警。近期,我们整合了原有的数据采集展示功能,新
Stella981 Stella981
4年前
SpreadJS 纯前端表格控件应用案例:MHT
由明厚天股份研发的数据填报采集平台,提供了便于用户操作的类Excel界面模式,可为用户提供规范、正确、完整的数据采集和填报模型,结合数据自动化抽样,可解析不同数据库、不同数据格式的数据,让数据填报流程更简单、更快速、更顺畅。下面,让我们一起来看看明厚天股份是如何在“MHTCP数据填报采集平台”中应用表格技术,实现“数据填报(https://www.
Wesley13 Wesley13
4年前
IP地址定位技术之一:基础数据采集
IP地理位置定位技术,包含基础数据采集、硬件系统搭建、应用场景划分和定位系统研发四项关键技术。基础数据采集为IP地理位置定位技术的研究提供基础数据支撑,是IP地址定位的基础性工作和关键技术。首先,按照不同的数据采集规则,针对不同数据源的数据格式,研究并实现一套自动化的智能化的数据采集技术;其次,对采集到的数据进行筛选、清洗和挖掘,形成基础数据库,为系统提
Easter79 Easter79
4年前
SwiftUI 跨组件数据传递
作者:Cyandev,iOS和MacOS开发者,目前就职于字节跳动0x00前言众所周知,SwiftUI的开发模式与React、Flutter非常相似,即都是声明式UI,由数据驱动(产生)视图,视图也会与数据自动保持同步,框架层会帮你处理“绑定”的问题。在声明式UI中不存在命令式地让一个视图变成xxx