{"id":13696231,"url":"https://github.com/MaricleZhang/LMForm","last_synced_at":"2025-05-03T16:32:56.373Z","repository":{"id":56918811,"uuid":"188219896","full_name":"MaricleZhang/LMForm","owner":"MaricleZhang","description":"iOS表单配置框架","archived":false,"fork":false,"pushed_at":"2020-10-22T05:53:18.000Z","size":102,"stargazers_count":139,"open_issues_count":5,"forks_count":22,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-29T04:48:34.703Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://mariclezhang.github.io/2020/10/12/LMForm%20-%20iOS%E8%A1%A8%E5%8D%95%E9%85%8D%E7%BD%AE%E6%A1%86%E6%9E%B6/","language":"Objective-C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MaricleZhang.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-05-23T11:22:37.000Z","updated_at":"2024-09-09T05:59:46.000Z","dependencies_parsed_at":"2022-08-20T21:50:32.032Z","dependency_job_id":null,"html_url":"https://github.com/MaricleZhang/LMForm","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MaricleZhang%2FLMForm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MaricleZhang%2FLMForm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MaricleZhang%2FLMForm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MaricleZhang%2FLMForm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MaricleZhang","download_url":"https://codeload.github.com/MaricleZhang/LMForm/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252216111,"owners_count":21713099,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-02T18:00:37.539Z","updated_at":"2025-05-03T16:32:55.777Z","avatar_url":"https://github.com/MaricleZhang.png","language":"Objective-C","funding_links":[],"categories":["UI Components"],"sub_categories":[],"readme":"# 更新日志\n\n## 2020-10-22\n\n1.兼容iOS 14.0\n\n2.设置UItextField设置_placeholderLabel.textColor 崩溃处理\n\n3._datePicker.preferredDatePickerStyle 支持13.4\n\n\n# LMForm\n\n## 背景\n\n通常，将一个页面需要编辑/录入多项信息的页面称为**表单**。iOS 实现表单大多数基于TableView,麻烦的是需要在```UITableViewDataSource```或者```UITableViewDelegate```的代理方法中写很多```if-else```，与cell耦合严重,不易获取用户已编辑的数据。如果表单页面的配置数据从服务端返回，不易实现。\n\n## 1. 介绍\n\nLMForm 是基于MVVM轻量级表单配置框架，把数据和事件整合为一个model，实现cell与model的绑定，只需操作model便可配置表单。项目地址：https://github.com/MaricleZhang/LMForm.git\n\n## 2. 结构\n\n![](https://user-gold-cdn.xitu.io/2019/5/31/16b0caa6a28e0d06?w=1290\u0026h=540\u0026f=png\u0026s=57217)\n\n * LMFormTypeManager : 负责管理类型与cellClass\n * LMFormModel：cell 的配置信息，事件回调，数据校验回调\n * Cell：遵循LMFormCellProtocol协议，实现不同的cell\n * LMFormTableView ：注册cell类型，通过model，渲染表单\n * LMFormValidator：负责对数据的校验\n\n## 3. 功能\n\n1. 支持动态配置model来实现表单。\n2. 支持配置文本、输入框、选择器、日期选择、地址选择等。\n3. 支持快速提取数据。\n4. 支持数据校验，可自定义校验格式。\n5. 支持完全自定义cell类型。\n\n## 4. 预览\n![form.gif](https://user-gold-cdn.xitu.io/2019/5/29/16b039f90940dd5b?w=442\u0026h=1000\u0026f=gif\u0026s=1500095)\n\n\n## 5. 安装\n ### CocoaPods\n在 Podfile 中进行如下导入：\n```\npod 'LMForm'\n```\n安装\n```\npod install\n```\n## 6. 使用\n在项目中导入```#import \"LMForm.h\" ```\n\n### 1. 配置数据源\n\n目前项目中集成以下类型：\n\n|类型 |宏定义|Cell Class |\n| ------ | ------ | ------ |\n| 文本 | kFormTypeText | LMFormCell |\n|输入框 | kFormTypeInput | LMFormInputCell |\n|选择器 | kFormTypeSelector | LMFormSelectorCell |\n|日期选择器 | kFormTypeDate | LMDateCell |\n|地址输入框 | kFormTypeAddressInput | LMFormAddressInputCell |\n|可变输入框 | kFormTypeTextView | LMFormTextViewCell |\n\n可根据需求来选择对应的类型，例如输入框的model配置代码如下：\n```\n  // 输入框\n- (LMFormModel *)loadInput\n{\n    LMFormModel *model = [LMFormModel new];\n    model.formType = kFormTypeInput;\n    model.title = @\"手机号\";\n    model.key = @\"mobile\";\n    model.value = @\"\";\n    model.placeholder = @\"请输入手机号\";\n    model.height = LM_XX_6(50);\n    model.message = @\"请输入正确的手机号\";\n    model.limitLength = 11;\n    model.validateBlock = ^BOOL(LMFormModel * _Nullable model) {\n        if (![LMFormValidator isMobile:model.value])\n        {\n            [LMWindowHud showHud:model.message];\n            return NO;\n        }\n        return YES;\n    };\n    return model;\n}\n```\n可根据需要设置UI，输入限制长度，自定义校验等。\n\n### 2. 创建tableview\n\n创建基于LMFormTableView 的tableview，并且赋值渲染数据，表单的创建完成。\n```\n    self.tableView.dataArray = self.dataArray;\n```\n### 3. 校验数据\n\n提交时，对数据源进行自定义校验，校验的逻辑是对```model.validateBlock```遍历回调。\n```\n/**\n 对数据源校验\n\n @param dataArray 数据源\n @return 全部校验通过返回YES，否则返回NO。\n */\n+ (BOOL)validateDataArray:(NSArray\u003cLMFormModel *\u003e *)dataArray\n{\n    for (LMFormModel * _Nonnull obj in dataArray)\n    {\n        if (obj.validateBlock)\n        {\n            if (!obj.validateBlock(obj)) return NO;\n        }\n    }\n    return YES;\n}\n```\n### 4. 获取数据源\n\n因为LMFormTableView中的cell与model绑定，只需遍历获取```value```即可。\n\n## 7. Cell 类型的介绍\n\n### 1. LMFormCell\n基类cell:其他类型cell继承该cell，主要功能显示文本，不可编辑。可根据需求配置相应UI和数据。\n```\n- (void)configModel:(LMFormModel *)model\n{\n    self.model = model;\n    \n    // data\n    self.titleLabel.text = model.title;\n    self.textField.placeholder = model.placeholder;\n    self.textField.text = model.value;\n    if (model.limitLength)\n    {\n        self.textField.limitLength = @(model.limitLength);\n    }\n    \n    // UI\n    self.line.hidden = model.hiddenLine;\n    self.line.backgroundColor = LM_ObjDefault(model.separatorLineColor, LM_UIColorFromHEX(0xF4F4F4));\n    self.titleLabel.textColor = LM_ObjDefault(model.leftTextColor, LM_UIColorFromHEX(0x666666));\n    self.textField.textColor = LM_ObjDefault(model.rightTextColor, LM_UIColorFromHEX(0x333333));\n    self.titleLabel.font = LM_ObjDefault(model.leftLabelFont, [UIFont systemFontOfSize:LM_XX_6(14)]);\n    self.titleLabel.font = LM_ObjDefault(model.rightLabelFont, [UIFont systemFontOfSize:LM_XX_6(14)]);\n}\n```\n### 2. LMFormInputCell\n输入Cell:可以编辑，可以对输入长度限制，输入的text更新为model的value。\n```\n- (void)textDidChanged:(UITextField *)textField\n{\n    self.model.value = textField.text;\n    if (self.model.valueDidChangedBlock)\n    {\n        self.model.valueDidChangedBlock(textField.text);\n    }\n}\n```\n### 3. LMFormSelectorCell\n选择器Cell:可以选择对应的item,需要配置数据```NSArray\u003cNSString *\u003e *selectList```,点击cell底部弹窗pickerView\n```\n- (void)tapSelectedAction\n{\n    LMDefaultPickerView *pickView = [[LMDefaultPickerView alloc] initWithDataArray:self.model.selectList];\n    @weakify(self)\n    [LMPopupView showPopupViewWithPickView:pickView title:self.model.placeholder confirmBlock:^{\n        @strongify(self)\n        NSString *text = self.model.selectList[pickView.selectIndex];\n        self.model.value = text;\n        self.textField.text = text;\n        if (self.model.valueDidChangedBlock)\n        {\n            self.model.valueDidChangedBlock(text);\n        }\n    } cancelBlock:^{\n        \n    }];\n}\n```\n### 4. LMDateCell\n选择日期Cell：与选择cell类似，底部弹窗datePickerView。目前只支持年月日。\n\n```\n- (void)tapSelectedAction\n{\n    @weakify(self)\n    [LMPopupView showPopupViewWithPickView:self.datePicker title:self.model.placeholder confirmBlock:^{\n        @strongify(self)\n        NSDate *date = self.datePicker.date;\n        NSDateFormatter *formatter = [[NSDateFormatter alloc] init];\n        [formatter setDateFormat:self.model.dateFormat ?: @\"yyyy-MM-dd\"];\n        NSString *text = [formatter stringFromDate:date];\n        self.model.value = text;\n        self.textField.text = text;\n    } cancelBlock:^{\n        \n    }];\n}\n```\n\n### 5. LMFormAddressInputCell \n\n地址输入cell：主要用来输入较多数字的信息，分两行显示。\n\n### 6. LMFormTextViewCell \n\n可变输入框cell：cell高度可随textview 高度变化而变化\n\n### 7.自定义cell\n\n#### 创建\nLMForm 支持cell的完全自定义，创建的自定义cell需要遵循协议```LMFormCellProtocol```，\n协议的方法必须实现，在自定义的cell中实现配置数据。如果LMFormModel中的属性不能满足需求，可以创建LMFormModel分类添加或者继承。个人比较推荐分类的做法。\n```\n/** 根据model 配置对应的cell  */\n- (void)configModel:(LMFormModel *)model;\n```\n#### 注册\n\nLMForm 维护一张注册表建立key与cellClass的一一对应关系，单例```LMFormTypeManager```中的```keyCellTypes```就是这个注册表。注册方法为\n```\n/**\n 自定义cell时注册方法，同一种cell只需要注册一次。cls 需继承UITableViewCell\n\n @param cls cell class\n @param key key\n */\n- (void)registerCellClass:(Class)cls forKey:(NSString *)key;\n```\n\n需要注意的是注册表是个字典，**key的定义不能重复**。\n\n ## 8. 项目地址：[Demo](https://github.com/MaricleZhang/LMForm.git) \n \n ## 9.联系\n \n 如有问题请邮件：maricle.zhang@gmail.com\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FMaricleZhang%2FLMForm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FMaricleZhang%2FLMForm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FMaricleZhang%2FLMForm/lists"}