MaterialFields
一个由 Material UI 驱动的文本输入和值选择框架,用于模块化验证层。
主要特性 | |
---|---|
Material UITextFields 和 UITextViews | |
Material UIPickerViews 和 UIDatePickers | |
字段包装类,允许简单的模块化验证 | |
错误功能,让用户知道输入有误 | |
内部 UI 状态管理 | |
模块化和可定制 | |
全 Swift | |
易于实现 |
将 MaterialFields 添加到项目中
打开您的 Podfile,然后在您的 target 下添加 MaterialFields
target 'Your Project' do
use_frameworks!
pod 'MaterialFields'
end
保存后,在项目目录下运行
pod install
入门指南
入门使用 MaterialFields 非常简单!有两个示例项目,一个程序化项目和一个使用 storyboards 的项目,展示了实现方法。
基本上,您只需做以下 4 件事来启用基本功能
- 实例化字段
- 设置其占位符(这是标题标签)和数据数组(如果为 PickerField)
- 设置其代理
- 实现 didEndEditing 代理方法以在用户输入完成后获取值!
Field
首先,我们定义一个字段。这是一个包装类,所有字段都遵循此类。这使得它们可以共享实现和功能,并且也简化了验证层。
字段类型
-
文本输入字段。这包括EntryField和AreaField。
-
选择类型字段。这包括PickerField和DateField
它们在正常状态下看起来相似,但在活动状态下每个都提供自己独特的功能。选择类型字段包含下拉菜单下的输入字段。它们提供了关闭自己的按钮,以及可选的清除按钮(通过设置isClearable = true
)。
状态
字段有带有只读标志的3种状态
- 非活动状态:
isActive == false
- 活跃状态,高亮可见:
isActive == true
- 错误状态:
hasError == true
所有状态逻辑和UI都由内部处理。您可以使用setError(withText:)设置错误状态,并且还可以手动删除它(字段会自动处理,请参见具体字段的详细说明)使用removeErrorUI()
值
它们返回两种类型的值
- 文本:通过
.text
访问,如果是一个EntryField、AreaField或PickerField, - 日期:通过
.date
访问,如果是一个DateField
大小
字段依赖其内在内容大小。这是因为如果打开选择器或在其错误状态下包含文本,它们的高度可能会发生变化。实现它们的最佳方法是将其放入UIStackViews中,让自动布局处理所有周围的事情。如果您想设置高度约束(通过自动布局或框架),则可能需要更多工作。下面是每个字段及其给定状态的高度。
字段类型 | 正常 | 错误 | 选择器打开 | 选择器打开 + 错误 |
---|---|---|---|---|
EntryField | 43.5 | 63.0 | 不适用 | 不适用 |
AreaField | 43.5+ | 63.0+ | 不适用 | 不适用 |
PickerField | 43.5 | 63.0 | 269.5 | 289 |
DateField | 43.5 | 63.0 | 269.5 | 289 |
颜色
由于所有字段看起来都一样,所以它们都有完全相同(具有小幅差异,考虑到其功能)的颜色属性。
EntryField
这是您的UITextField。大多数UITextField功能已转发到EntryField。
所有的 UITextField 委托都在这里,只是重新命名了。
额外功能
- 单位标签:将
unit
属性设置为字符串以显示单位标签,该标签位于右侧。 - 货币标签:设置
isMonetary = true
,在左侧显示美元符号。
它们的颜色也可以通过 monetaryColor
或 unitColor
覆盖
响应者行为
输入字段的行为与 UITextFields 相同,becomeFirstResponder()
将激活字段,而 resignFirstResponder()
将停用字段。
AreaField
这是一个只有文本输入功能的 UITextView,因此是多行输入字段。与输入字段不同,它不支持 isMonetary
或 units
。
这里包含所有文本输入相关的委托。
响应者行为
AreaField 的行为与 UITextView 相同,becomeFirstResponder()
将激活字段,而 resignFirstResponder()
将停用字段。
PickerField
这是您的 UIPickerView,只支持 1 列。大多数配置工作都已经提取出来,留下很少的实现逻辑。您只需要将其 data
数组设置为您的字符串数组,其余的都由您处理。PickerField 包含一个用于显示拾取内容的 EntryField。
这与您习惯的不同,因为您不再需要实现数据源协议。
您有以下
-
shouldBeginEditing:是否打开它
-
didEndEditing:用户通过点击完成按钮或键盘弹出而关闭了字段(有关键盘行为,请参阅)
-
cleared:用户点击了清除按钮(如果
isClearable = true
) -
selectedRowForIndexPath:用户在拾取器中选择了不同的值
额外功能
isManualEntryCapable
这将向数据源末尾添加一个“手动输入”选项,如果选中,则会弹出键盘并激活 PickerField 内嵌的 EntryField。手动输入行标签可以通过senalEntryOptionName
覆盖。
您可以使用 indexSelected
观察当前索引,使用 setIndexTo
设置索引,使用 setIndexToManual()
设置索引到手动输入。
响应者行为
becomeFirstResponder()
将激活并打开拾取器/EntryField,如果在手动输入closeFirstResponder()
将停用和关闭拾取器/EntryField,如果在手动输入
键盘行为
PickerFields 注册键盘显示通知。如果它们不在手动输入,它们将关闭自身并在键盘弹出时触发它们的 didEndEditing 委托。
DateField
这是您的 UIDatePicker。您可以使用与您所习惯的 UIDatePicker 一样的一切操作,属性名也是相同的。
这反映了 PickerField 代理。
您有以下
-
shouldBeginEditing:是否打开它
-
didEndEditing:用户通过点击完成按钮或键盘弹出而关闭了字段(有关键盘行为,请参阅)
-
cleared:用户点击了清除按钮(如果
isClearable = true
) -
dateChanged : 用户选择了不同的日期
响应者行为
becomeFirstResponder()
将激活并打开拾取器closeFirstResponder()
将禁用并关闭拾取器
键盘行为
DateFields 注册键盘显示通知。键盘出现时,它们将自行关闭并触发 didEndEditing 代理。
验证层
由于所有字段都遵循 Field 类,因此直接与 Fields 关联的验证层从未如此简单!
让我们定义 3 个字段,一个 EntryField,一个 AreaField 和一个 PickerField
let entryField = EntryField()
let areaField = AreaField()
let pickerField = PickerField()
让我们还定义一个 CaseIterable 枚举
extension CaseIterable where AllCases.Element: Equatable {
static func make(index: Int) -> Self { //get the key from the case index
let a = Self.allCases
return a[a.index(a.startIndex, offsetBy: index)]
}
func index() -> Int { //get the index from the case
let a = Self.allCases
return a.distance(from: a.startIndex, to: a.firstIndex(of: self)!)
}
}
enum FieldKeys : String, CaseIterable {
case entry
case area
case picker
}
使用我们的 CaseIterable 枚举,我们可以将验证键用作字段的标签!
entryField.tag = FieldKeys.entry.index()
areaField.tag = FieldKeys.area.index()
pickerField.tag = FieldKeys.picker.index()
假设我们需要在提交模型更改之前验证一个通用的字符串(在我们的核心数据模型中设置了正则表达式)使用 NSManagedObject 的扩展。
extension NSManagedObject {
func validateString(view: Field, key: String){
var value = view.text as AnyObject?
do {
try self.validateValue(&(value), forKey: key)
} catch {
view.setError(withText: "please try again")
print(error)
return
}
self.setValue(value, forKey: key)
}
}
现在在任意字段的 didEndEditing 代理方法中,我们只需两行代码即可验证我们的输入。
//EntryFieldDelegates
func entryFieldDidEndEditing(_ view: EntryField){
let key = FieldKeys.make(index: view.tag) //the key reconstructed from our enum used for the field tags
ourNSManagedObject.validateString(view,key)
}
//AreaFieldDelegates
func areaFieldDidEndEditing(_ view: AreaField){
let key = FieldKeys.make(index: view.tag) //the key reconstructed from our enum used for the field tags
ourNSManagedObject.validateString(view,key)
}
//PickerFieldDelegates
func pickerFieldDidEndEditing(_ view: PickerField){
let key = FieldKeys.make(index: view.tag) //the key reconstructed from our enum used for the field tags
ourNSManagedObject.validateString(view,key)
}
现在我们有一个能够进行数据模型验证和 UI 反馈的验证层!
文档
MaterialFields 使用 Jazzy 全面文档化 在此处。
要重新生成文档,请在项目根目录中运行
jazzy --source-directory 'MaterialFields/' --documentation=Guides/*.md -g 'https://github.com/barbulescualex/MaterialFields' -m 'MaterialFields'
许可
MaterialFields 根据 MIT 许可证开源。