0%

iOS 表单开发 基础篇

       移动端大部分页面是由列表、表单、对话框展示,它们也是开发中最频繁开发的部分。说说表单,它是提供用户输入数据后提交的页面,常用于注册、登录、购物、评论等等。将表单抛开复杂控件和动画等元素,其主要由输入框、选择框、按钮构成,逻辑也就是输入、选择要提交的内容,点击提交即完成,这只是简化的逻辑。而完整的表单,其实可能根据业务不同,会有不同的细节处理,如加密,数据校验,UI 联调,状态提醒等等。那接下来介绍几个比较常见的表单设置与开发。

输入框

UITextField & UITextView

       分别是单行、多行文本输入与展示的控件

1
let testTF = UITextField(frame: CGRect(x: 0, y: 0, width: 100, height: 30))

输入的键盘类型

1
testTF.keyboardType = .default //可查看 UIKeyboardType

输入结束的键盘回收

       UITextFieldDelegate

1
2
3
4
public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return false
}

       在使用键盘回收的时候,可能会有输入面板的升降等类似 UI 的变化。当使用原生的键盘时候都是点击 return 作为确定按钮回收键盘。可是当使用第三方键盘时候,有多一个工具区域(即在正常键盘上方),其会有回收按钮,它不会触发上述的回调函数。因此需要增加如下回调

1
2
3
- (void)textFieldDidEndEditing:(UITextField *)textField {
// doAction
}

键盘

键盘监听 & 回调高度变化的逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import UIKit

class QHKeyboardEvent: NSObject {

class func removeKeyboardNotificationCenter(object: Any) {
NotificationCenter.default.removeObserver(object, name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.removeObserver(object, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}

class func addKeyboardNotificationCenter(object: Any, keyboardWillShow willShow: Selector, keyboardWillHide willHide: Selector) {
NotificationCenter.default.addObserver(object, selector: willShow, name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(object, selector: willHide, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}

class func keyboardActionWithNotification(_ notification: Notification, complete: (_ hKeyB: CGFloat) -> Void) {
if let userInfo = notification.userInfo {
let animationCurveObject = userInfo[UIKeyboardAnimationCurveUserInfoKey] as! NSValue
let animationDurationObject = userInfo[UIKeyboardAnimationDurationUserInfoKey] as! NSValue
let keyboardEndRectObject = userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue

var animationCurve = UIViewAnimationCurve.easeOut
var animationDuration = 0.0
var keyboardEndRect = CGRect(x: 0, y: 0, width: 0, height: 0)
animationCurveObject.getValue(&animationCurve)
animationDurationObject.getValue(&animationDuration)
keyboardEndRectObject.getValue(&keyboardEndRect)

var hKeyB = 0 as CGFloat
hKeyB = keyboardEndRect.size.height

UIView.beginAnimations("qhKeyboardAction", context: nil)
UIView.setAnimationDuration(animationDuration)
UIView.setAnimationCurve(animationCurve)
complete(hKeyB)
UIView.commitAnimations()
}
}
}

       使用

1
2
3
4
5
6
7
func p_addNotification() {
QHKeyboardEvent.addKeyboardNotificationCenter(object: self, keyboardWillShow: #selector(self.keyboardWillShow(notification:)), keyboardWillHide: #selector(self.keyboardWillHide(notification:)))
}

func p_removeNotification() {
QHKeyboardEvent.removeKeyboardNotificationCenter(object: self)
}

处理回调

键盘弹出或者回收时,使用回调的高度来控制如下属性,从而达到输入面板的上升与下降

1
2
3
4
1、使用约束
@IBOutlet weak var contentVTopLC: NSLayoutConstraint!
2、frame 进行修改
view.frame

按钮

单色状态

       使用 qhImageWithColor & setBackgroundImage 来设置按钮各种的单色状态: normal disable highlight:

1
2
3
4
// 正常状态的颜色
doBtn.setBackgroundImage(SHRewardCashViewController.qhImageWithColor(UIColor(hexValue: 0x189AFF)), for: UIControlState.normal)

// 禁止点击状态的颜色doBtn.setBackgroundImage(SHRewardCashViewController.qhImageWithColor(UIColor(hexValue: 0x189AFF, alpha: 0.5)), for: UIControlState.disabled)
1
2
3
4
5
6
7
8
9
10
11
class func qhImageWithColor(_ color: UIColor) -> UIImage? {
let rect = CGRect(x: 0, y: 0, width: 100, height: 100)
UIGraphicsBeginImageContext(rect.size)
let context = UIGraphicsGetCurrentContext()
context?.setFillColor(color.cgColor)
context?.fill(rect)

let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}

圆角

1
2
3
4
5
// 圆角
doBtn.layer.masksToBounds = true
doBtn.layer.cornerRadius = 10
// 边距
doBtn.layer.borderWidth = 1

       而使用 storyboard 或者 xib 的,可以在属性面板 User Defined Runtime Attributes 里添加,如下:

Key Path Type Value
layer.masksToBounds Boolean
layer.cornerRadius Number 10

       但是 cornerRadius 如果需要计算的,就需要使用代码进行设置。

数据校验

       在提交数据的时候需要对数据的校验

1、前置校验限制

       通过 UITextFieldDelegate 的限制输入

1
2
3
4
5
6
7
8
9
10
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if textField == accountTF {
if let phoneNumber = textField.text {
if phoneNumber.count >= 11 && !string.isEmpty {
return false
}
}
}
return true
}

2、对于满足条件才允许点击提交按钮

       一般通过 UIControlEvents.editingChanged 状态通知获得输入变化的实时校验控制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
accountTF.addTarget(self, action: #selector(self.updateLoginButtonAction(sender:)), for: UIControlEvents.editingChanged)

func p_updateLoginButton() {
if accountTF.text?.isEmpty == true || passwordTF.text?.isEmpty == true {
sureButton.isEnabled = false
}
else if p_isHiddenPictureCode() == false && pictureTF.text?.isEmpty == true {
sureButton.isEnabled = false
}
else {
sureButton.isEnabled = true
}
}

@objc func updateLoginButtonAction(sender: UITextField) {
p_updateLoginButton()
}

       多个输入联动按钮 UIButton 是否点击,即给多个 UITextField 添加监听来控制

RxSwift

       由于上述的方法都是使用系统的回调与通知来控制,而越来越大第三方库提供更便捷的方法,如 RxSwift

1、单个输入

1
2
3
4
5
6
7
8
9
10
11
cashTF.rx.text.orEmpty.changed
.subscribe(onNext: {
if let b = Float($0) {
if b > self.balance {
self.errorTipL.isHidden = false
return
}
}
self.errorTipL.isHidden = true
})
.disposed(by: disposeBag)

2、多个联动

1
2
3
4
5
6
7
8
9
10
11
Observable.combineLatest(cashTF.rx.text.orEmpty, nameL.rx.text.orEmpty, accountL.rx.text.orEmpty) { (cash, name, account) -> Bool in
if cash.count > 0, name.count > 0, account.count > 0, self.errorTipL.isHidden == true {
return true
}
return false
}
.map {
self.doBtn.isEnabled = $0
}
.bind {}
.disposed(by: disposeBag)

弹层

       弹层的动画工具:该工具是实现弹层控件在 底部 或者 四周 的弹出动画,类似分享或者直播间的用户面板等。

       其实是针对 动画 的统一封装,这里主要使用 UIView 的 animation,但是由于封装,可以方便扩展其他动画,如修改为 Keyframe 等。

       另外该工具也针对 UI 布局比较常用的三种,分别是:Frame、Autolayout & Masonry 进行适配 & 实现。

[TODO]

校验内容:手机号码、邮箱、身份证

根据填入数据显示其他输入控件,如验证码等

图片、头像、视频

提交后数据更新

对话框形式、动画、居中布局