MaterialFields 1.0.1

MaterialFields 1.0.1

Alex Barbulescu 维护。



  • 作者
  • Alexandru Barbulescu

MaterialFields

PromoGif

一个由 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 件事来启用基本功能

  1. 实例化字段
  2. 设置其占位符(这是标题标签)和数据数组(如果为 PickerField)
  3. 设置其代理
  4. 实现 didEndEditing 代理方法以在用户输入完成后获取值!

Field


首先,我们定义一个字段。这是一个包装类,所有字段都遵循此类。这使得它们可以共享实现和功能,并且也简化了验证层。

字段类型

  1. 文本输入字段。这包括EntryFieldAreaField

  2. 选择类型字段。这包括PickerFieldDateField

它们在正常状态下看起来相似,但在活动状态下每个都提供自己独特的功能。选择类型字段包含下拉菜单下的输入字段。它们提供了关闭自己的按钮,以及可选的清除按钮(通过设置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


EntryFieldDemo EntryFieldDemoCost

这是您的UITextField。大多数UITextField功能已转发到EntryField。

EntryFieldDelegate

所有的 UITextField 委托都在这里,只是重新命名了。

额外功能

  • 单位标签:将 unit 属性设置为字符串以显示单位标签,该标签位于右侧。
  • 货币标签:设置 isMonetary = true,在左侧显示美元符号。

它们的颜色也可以通过 monetaryColorunitColor 覆盖

响应者行为

输入字段的行为与 UITextFields 相同,becomeFirstResponder() 将激活字段,而 resignFirstResponder() 将停用字段。

AreaField


AreaFieldDemo AreaFieldDemoError

这是一个只有文本输入功能的 UITextView,因此是多行输入字段。与输入字段不同,它不支持 isMonetaryunits

AreaFieldDelegate

这里包含所有文本输入相关的委托。

响应者行为

AreaField 的行为与 UITextView 相同,becomeFirstResponder() 将激活字段,而 resignFirstResponder() 将停用字段。

PickerField


PickerFieldDemo PickerFieldDemo

PickerFieldDemo PickerFieldDemo

这是您的 UIPickerView,只支持 1 列。大多数配置工作都已经提取出来,留下很少的实现逻辑。您只需要将其 data 数组设置为您的字符串数组,其余的都由您处理。PickerField 包含一个用于显示拾取内容的 EntryField。

PickerFieldDelegate

这与您习惯的不同,因为您不再需要实现数据源协议。

您有以下

  • shouldBeginEditing:是否打开它

  • didEndEditing:用户通过点击完成按钮或键盘弹出而关闭了字段(有关键盘行为,请参阅)

  • cleared:用户点击了清除按钮(如果 isClearable = true

  • selectedRowForIndexPath:用户在拾取器中选择了不同的值

额外功能

  • isManualEntryCapable 这将向数据源末尾添加一个“手动输入”选项,如果选中,则会弹出键盘并激活 PickerField 内嵌的 EntryField。手动输入行标签可以通过 senalEntryOptionName 覆盖。

您可以使用 indexSelected 观察当前索引,使用 setIndexTo 设置索引,使用 setIndexToManual() 设置索引到手动输入。

响应者行为

  • becomeFirstResponder() 将激活并打开拾取器/EntryField,如果在手动输入
  • closeFirstResponder() 将停用和关闭拾取器/EntryField,如果在手动输入

键盘行为

PickerFields 注册键盘显示通知。如果它们不在手动输入,它们将关闭自身并在键盘弹出时触发它们的 didEndEditing 委托。

DateField


DateFieldDemo DateFieldDemo

DateFieldDemo

这是您的 UIDatePicker。您可以使用与您所习惯的 UIDatePicker 一样的一切操作,属性名也是相同的。

DateFieldDelegate

这反映了 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 许可证开源。