通用UI 0.2.5

通用UI 0.2.5

托马斯·莱特雷维护。



通用UI 0.2.5

  • 作者:
  • tlextrait
Generic User Interface

GenericUI

CI Status Version Swift License Platform

通用UI为您提供用于iOS项目的美观且通用的UI元素。目前它主要关注输入和表格,但还有更多功能即将推出。

内容

要求

  • Swift 5.2
  • iOS 9.0+

组件

目前只有几个组件可用。它们拥有超强的可定制性,应该能让您节省大量时间和代码。

输入

UIInputField<输出类型>

这是一个非常简单的泛型扩展,用于UITextField,旨在将输入转换为泛型类型。

UIActiveInput<输出类型>

这是一个更复杂的输入,根据UIInputField<输出类型>结合了多个视图。它非常可定制,但默认提供良好设计、标签、活动状态的动画指示器等。它公开了原始文本字段的API,包括无障碍功能。

表单

UIQuickForm<模型类型>

这是一个简单的组件,允许您构建美丽的表单,可以从用户处收集通用的模型。UIQuickForm为您处理所有布局。

更多...

更多内容即将到来...

示例

字符串输入

下面的代码会创建一个标签为“FirstName”的输入框,允许用户输入文本内容,输出结果为 String

let input = UIActiveInput<String>("Firstname")
addSubview(input)
let firstname: String = input.output // returns String?

无符号整数输入

以下是一个从用户那里收集无符号整数的输入示例。输出结果为 UInt。该 UIActiveInput 智能地自动将键盘设置为不带小数点的数字键盘。

let input = UIActiveInput<UInt>("Age")
addSubview(input)
let age: UInt = input.output // returns UInt?

T自定义对象输入

您可以从 UIActiveInput 收集自己的模型类型,但该类型需要符合几个协议,特别是:StringTwoWayConvertibleBestKeyboardType。这些协议的目的是确保您的对象提供从 String(因为 UIActiveInput 是基于原生 UITextField 的)转换的方法,并指定最佳使用的 iOS 键盘类型。StringTwoWayConvertible 是您提供自定义字符串转换的方式。

通过扩展,您也可以使现有或第三方类型能够通过 UIActiveInput 返回。

示例

class MyCustomType : StringTwoWayConvertible, BestKeyboardType {
    var number: Double
    
    init?(_ text: String) {
        // Write your own String -> Object transform
        guard let n = Double(text) else {
            return
        }
        number = n
    }
    
    var description: String {
        // Write your own Object -> String transform
        return "\(number)"
    }
    
    static var bestKeyboardType: UIKeyboardType {
        return .decimalPad
    }
}

let input = UIActiveInput<MyCustomType>()

自定义 UIActiveInput

Firstname Field

UIActiveInput 深度可定制,直接基于原生 UITextField 构建。它本质上是一个 UIView,它包裹了一个 UILabel、一个 UITextField 和一个用来显示输入是否激活的 UIView

样式

以下是一些您可以访问并自定义样式的属性

  • input.label公开UILabel对象,您可以直接自定义甚至移除。
  • input.inputColor是文本框的背景颜色。
  • input.backgroundColor是整个元素的背景颜色。
  • input.activeColor是小竖直指示器的颜色,默认为蓝色。
  • input.indicatorWidth是活动指示器的宽度,默认为2.0。
  • input.forcedLabelWidth允许您强制使标签具有一定的宽度。这在您有多个输入框且希望所有文本框的左侧对齐时很有用。
  • input.placeHolder设置文本输入的占位符。
  • input.font设置文本输入的字体。
  • input.textColor设置文本输入的颜色。
  • input.layer如果需要执行更深入的定制,它为您提供了整个元素的设计层。
  • input.inputLayer为您提供了文本输入的设计层。
  • input.keyboardType允许您为文本输入设置键盘类型(注意这通常自动设置,但您可以手动设置以覆盖它)。
  • input.layoutMargins允许您自定义元素内的边距(从UIActiveInput的边缘到标签和文本输入之间的空间)。

还有更多无法在此列出...

UIActiveInputUITextField的一个子类,而UITextFieldUIView的一个子类,因此在UIActiveInput中也找到了您在这些类上期望找到的所有属性和方法。

文本输入代理

input.delegate允许您为嵌入式的文本框指定代理。

触摸事件

默认情况下,如果在UIActiveInput上的任何地方(包括标签)点击,文本框将变为响应者。您也可以通过调用input.becomeFirstResponder()input.resignFirstResponder()来程序化地这样做。

无障碍访问

UIActiveInput 为您提供所有标准的访问性功能,并将所有这些调用传递给嵌入的文本输入(盲用户应“看到” UIActiveInput 就像常规的 UITextField 一样)。

一个简单的表单

CGSize 表单

simple form

以下是一个包含两个输入的非常简单的表单示例。此表单的目标是收集一个 CGSize,一个用于宽度,一个用于高度。

class ViewController : UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        //...
        
        let form = UIQuickFormView<CGSize>()
        view.addSubview(form)
        
        // Form styling and layout
        form.backgroundColor = .green
        form.layer.cornerRadius = 3.0
        form.translatesAutoresizingMaskIntoConstraints = false
        form.topAnchor.constraint(equalTo: view.layoutMarginsGuide.bottomAnchor, constant: 10.0).isActive = true
        form.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor, constant: 8.0).isActive = true
        form.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor, constant: -8.0).isActive = true

        let widthInput = UIActiveInput<CGFloat>(label: "WIDTH")
        let heightInput = UIActiveInput<CGFloat>(label: "HEIGHT")

        // Bind the inputs
        let widthInputId = form.bind(input: widthInput) { (size: inout CGSize, input: UIActiveInput<CGFloat>) in
            guard let width = input.output else {
                // handle any errors here
                return (false, nil)
            }
            size.width = width
            return (true, nil)
        }
        let heightInputId = form.bind(input: heightInput) { (size: inout CGSize, input: UIActiveInput<CGFloat>) in
            guard let height = input.output else {
                // handle any errors here
                return (false, nil)
            }
            size.height = height
            return (true, nil)
        }

        // Lay out the inputs in the form (both inputs go on the same line here)
        form.addRow([FormElement(widthInputId), FormElement(heightInputId)])
        form.setRecommendedContentPriorities()
        form.build() // sets up autolayout constraints for all the views within the form

        // When you want to resolve the form to a CGSize:
        var size = CGSize(width: 0, height: 0)
        let success = form.resolve(model: &size)    // returns a tuple (Bool, [Error])
    }
    
}

处理错误

为处理糟糕的用户输入创建自己的错误类型。错误处理是在绑定处进行的。当表单解决时,您可以获取所有错误的数组。

enum PersonError : Error {
    case tooOld, nilInput
}
...
let ageId = form.bind(input: ageInput) { (person, input) in
    guard let age = input.output else {
        return (false, PersonError.nilInput)
    }
    if age > 120 {
        return (false, PersonError.tooOld)
    }
    person.age = age
    return (true, nil)
}
...
let success = form.resolve(model: &person)
// success is a tuple (Bool, [Error])
if success.0 {
    // everything looks good!
} else {
    for error in success.1 {
        ...
    }
}

将原生输入添加到表单中

您可以将任何类型的输入添加到 UIQuickFormView 中,包括原生和第三方。

let textInput = UITextField(frame: .zero)
let inputIndentifier = form.bind(input: textInput) { (..., input: UITextField) in
    guard let text = input.text else {
        ...
    }
    ...
}
form.addRow([..., FormElement(inputIndentifier), ...])

将视图添加到表单中

label

您可以将任何类型的视图添加到 UIQuickFormView 中。

let label = UILabel(frame: .zero)
let viewIndentifier = form.bind(view: label)
form.addRow([..., FormElement(viewIndentifier), ...])

自定义表单元素大小

custom element size

您可以根据需要调整表单中每个元素在行中所占的水平空间。默认尺寸值为 1。如果一行中的所有元素尺寸相同,则它们将平均分配水平空间。

form.addRow([FormElement(input, size: 2), FormElement(view, size: 1), ...])

占位符

spacer

UIQuickFormView 提供了创建占位符的便捷方式。

form.addRow([FormElement.makeSpacer(size: 3), FormElement(view, size: 1), ...])

即将推出

  • 当前状态,无法在表单解决前知道是否有输入错误。一个当输入变化时通知调用代码是否出现错误的功能即将推出。表单将期望为每个输入绑定以及可选验证器。
  • 自动绑定。
  • 通用模态。
  • 通用表视图和表视图控制器。