LMForm
背景
通常啡氢,將一個頁面需要編輯/錄入多項信息的頁面稱為表單。iOS 實現(xiàn)表單大多數(shù)基于TableView,麻煩的是需要在UITableViewDataSource
或者UITableViewDelegate
的代理方法中寫很多if-else
掰曾,與cell耦合嚴(yán)重,不易獲取用戶已編輯的數(shù)據(jù)旭蠕。如果表單頁面的配置數(shù)據(jù)從服務(wù)端返回,不易實現(xiàn)旷坦。
1. 介紹
LMForm 是基于MVVM輕量級表單配置框架掏熬,把數(shù)據(jù)和事件整合為一個model,實現(xiàn)cell與model的綁定塞蹭,只需操作model便可配置表單孽江。項目地址:https://github.com/MaricleZhang/LMForm.git
2. 結(jié)構(gòu)
- LMFormTypeManager : 負(fù)責(zé)管理類型與cellClass
- LMFormModel:cell 的配置信息,事件回調(diào)番电,數(shù)據(jù)校驗回調(diào)
- Cell:遵循LMFormCellProtocol協(xié)議,實現(xiàn)不同的cell
- LMFormTableView :注冊cell類型辆琅,通過model漱办,渲染表單
- LMFormValidator:負(fù)責(zé)對數(shù)據(jù)的校驗
3. 功能
- 支持動態(tài)配置model來實現(xiàn)表單。
- 支持配置文本婉烟、輸入框娩井、選擇器、日期選擇似袁、地址選擇等洞辣。
- 支持快速提取數(shù)據(jù)。
- 支持?jǐn)?shù)據(jù)校驗昙衅,可自定義校驗格式扬霜。
- 支持完全自定義cell類型。
4. 預(yù)覽
5. 安裝
CocoaPods
在 Podfile 中進行如下導(dǎo)入:
pod 'LMForm'
安裝
pod install
6. 使用
在項目中導(dǎo)入#import "LMForm.h"
1. 配置數(shù)據(jù)源
目前項目中集成以下類型:
類型 | 宏定義 | Cell Class |
---|---|---|
文本 | kFormTypeText | LMFormCell |
輸入框 | kFormTypeInput | LMFormInputCell |
選擇器 | kFormTypeSelector | LMFormSelectorCell |
日期選擇器 | kFormTypeDate | LMDateCell |
地址輸入框 | kFormTypeAddressInput | LMFormAddressInputCell |
可根據(jù)需求來選擇對應(yīng)的類型而涉,例如輸入框的model配置代碼如下:
// 輸入框
- (LMFormModel *)loadInput
{
LMFormModel *model = [LMFormModel new];
model.formType = kFormTypeInput;
model.title = @"手機號";
model.key = @"mobile";
model.value = @"";
model.placeholder = @"請輸入手機號";
model.height = LM_XX_6(50);
model.message = @"請輸入正確的手機號";
model.limitLength = 11;
model.validateBlock = ^BOOL(LMFormModel * _Nullable model) {
if (![LMFormValidator isMobile:model.value])
{
[LMWindowHud showHud:model.message];
return NO;
}
return YES;
};
return model;
}
可根據(jù)需要設(shè)置UI著瓶,輸入限制長度,自定義校驗等啼县。
2. 創(chuàng)建tableview
創(chuàng)建基于LMFormTableView 的tableview材原,并且賦值渲染數(shù)據(jù),表單的創(chuàng)建完成季眷。
self.tableView.dataArray = self.dataArray;
3. 校驗數(shù)據(jù)
提交時余蟹,對數(shù)據(jù)源進行自定義校驗,校驗的邏輯是對model.validateBlock
遍歷回調(diào)子刮。
/**
對數(shù)據(jù)源校驗
@param dataArray 數(shù)據(jù)源
@return 全部校驗通過返回YES威酒,否則返回NO。
*/
+ (BOOL)validateDataArray:(NSArray<LMFormModel *> *)dataArray
{
for (LMFormModel * _Nonnull obj in dataArray)
{
if (obj.validateBlock)
{
if (!obj.validateBlock(obj)) return NO;
}
}
return YES;
}
4. 獲取數(shù)據(jù)源
因為LMFormTableView中的cell與model綁定,只需遍歷獲取value
即可兼搏。
7. Cell 類型的介紹
1. LMFormCell
基類cell:其他類型cell繼承該cell卵慰,主要功能顯示文本,不可編輯佛呻∩雅螅可根據(jù)需求配置相應(yīng)UI和數(shù)據(jù)。
- (void)configModel:(LMFormModel *)model
{
self.model = model;
// data
self.titleLabel.text = model.title;
self.textField.placeholder = model.placeholder;
self.textField.text = model.value;
if (model.limitLength)
{
self.textField.limitLength = @(model.limitLength);
}
// UI
self.line.hidden = model.hiddenLine;
self.line.backgroundColor = LM_ObjDefault(model.separatorLineColor, LM_UIColorFromHEX(0xF4F4F4));
self.titleLabel.textColor = LM_ObjDefault(model.leftTextColor, LM_UIColorFromHEX(0x666666));
self.textField.textColor = LM_ObjDefault(model.rightTextColor, LM_UIColorFromHEX(0x333333));
self.titleLabel.font = LM_ObjDefault(model.leftLabelFont, [UIFont systemFontOfSize:LM_XX_6(14)]);
self.titleLabel.font = LM_ObjDefault(model.rightLabelFont, [UIFont systemFontOfSize:LM_XX_6(14)]);
}
2. LMFormInputCell
輸入Cell:可以編輯吓著,可以對輸入長度限制鲤嫡,輸入的text更新為model的value。
- (void)textDidChanged:(UITextField *)textField
{
self.model.value = textField.text;
if (self.model.valueDidChangedBlock)
{
self.model.valueDidChangedBlock(textField.text);
}
}
3. LMFormSelectorCell
選擇器Cell:可以選擇對應(yīng)的item,需要配置數(shù)據(jù)NSArray<NSString *> *selectList
,點擊cell底部彈窗pickerView
- (void)tapSelectedAction
{
LMDefaultPickerView *pickView = [[LMDefaultPickerView alloc] initWithDataArray:self.model.selectList];
@weakify(self)
[LMPopupView showPopupViewWithPickView:pickView title:self.model.placeholder confirmBlock:^{
@strongify(self)
NSString *text = self.model.selectList[pickView.selectIndex];
self.model.value = text;
self.textField.text = text;
if (self.model.valueDidChangedBlock)
{
self.model.valueDidChangedBlock(text);
}
} cancelBlock:^{
}];
}
4. LMDateCell
選擇日期Cell:與選擇cell類似绑莺,底部彈窗datePickerView暖眼。目前只支持年月日。
- (void)tapSelectedAction
{
@weakify(self)
[LMPopupView showPopupViewWithPickView:self.datePicker title:self.model.placeholder confirmBlock:^{
@strongify(self)
NSDate *date = self.datePicker.date;
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:self.model.dateFormat ?: @"yyyy-MM-dd"];
NSString *text = [formatter stringFromDate:date];
self.model.value = text;
self.textField.text = text;
} cancelBlock:^{
}];
}
5. LMFormAddressInputCell
地址輸入cell:主要用來輸入較多數(shù)字的信息纺裁,分兩行顯示诫肠。
6.自定義cell
創(chuàng)建
LMForm 支持cell的完全自定義,創(chuàng)建的自定義cell需要遵循協(xié)議LMFormCellProtocol
欺缘,
協(xié)議的方法必須實現(xiàn)栋豫,在自定義的cell中實現(xiàn)配置數(shù)據(jù)。如果LMFormModel中的屬性不能滿足需求谚殊,可以創(chuàng)建LMFormModel分類添加或者繼承丧鸯。個人比較推薦分類的做法。
/** 根據(jù)model 配置對應(yīng)的cell */
- (void)configModel:(LMFormModel *)model;
注冊
LMForm 維護一張注冊表建立key與cellClass的一一對應(yīng)關(guān)系嫩絮,單例LMFormTypeManager
中的keyCellTypes
就是這個注冊表丛肢。注冊方法為
/**
自定義cell時注冊方法,同一種cell只需要注冊一次剿干。cls 需繼承UITableViewCell
@param cls cell class
@param key key
*/
- (void)registerCellClass:(Class)cls forKey:(NSString *)key;
需要注意的是注冊表是個字典蜂怎,key的定義不能重復(fù)。