最近开发中做了很多表单页面,各种UITextField,各种风格,用原生的写,确实写的还不错,但是每次都要花一天时间去调试,效果还是可以的,最近在github上逛,看到了个宇宙第一的表单组件,据说能带你飞,人家是这么宣传的......
XLForm is the most flexible and powerful iOS library to create dynamic table-view forms. The goal of the library is to get the same power of hand-made forms butspending 1/10 of the time.
XLForm provides a very powerful DSL (Domain Specific Language) used to create a form. It keeps track of this specification on runtime,updating the UI on the fly.
先看图
来看看人家自己封装好的集中强大的表单cell
#import "XLForm.h"
// JVFloatLabeledTextField 普通的文本输入框,自带浮动动画
NSString *const XLFormRowDescriptorTypeText = @"text";
// add的时候展示名字的 JVFloatLabeledTextField
NSString *const XLFormRowDescriptorTypeName = @"name";
// 填写URL的cell
NSString *const XLFormRowDescriptorTypeURL = @"url";
NSString *const XLFormRowDescriptorTypeEmail = @"email";
NSString *const XLFormRowDescriptorTypePassword = @"password";
NSString *const XLFormRowDescriptorTypeNumber = @"number";
NSString *const XLFormRowDescriptorTypePhone = @"phone";
NSString *const XLFormRowDescriptorTypeTwitter = @"twitter";
NSString *const XLFormRowDescriptorTypeAccount = @"account";
NSString *const XLFormRowDescriptorTypeInteger = @"integer";
// 选择更换头像图片的cell
NSString *const XLFormRowDescriptorTypeImage = @"image";
NSString *const XLFormRowDescriptorTypeDecimal = @"decimal";
// JVFloat对应的textView的cell
NSString *const XLFormRowDescriptorTypeTextView = @"textView";
NSString *const XLFormRowDescriptorTypeZipCode = @"zipCode";
// 非常普通的点击push选择
NSString *const XLFormRowDescriptorTypeSelectorPush = @"selectorPush";
NSString *const XLFormRowDescriptorTypeSelectorPopover = @"selectorPopover";
NSString *const XLFormRowDescriptorTypeSelectorActionSheet = @"selectorActionSheet";
NSString *const XLFormRowDescriptorTypeSelectorAlertView = @"selectorAlertView";
NSString *const XLFormRowDescriptorTypeSelectorPickerView = @"selectorPickerView";
NSString *const XLFormRowDescriptorTypeSelectorPickerViewInline = @"selectorPickerViewInline";
NSString *const XLFormRowDescriptorTypeMultipleSelector = @"multipleSelector";
NSString *const XLFormRowDescriptorTypeMultipleSelectorPopover = @"multipleSelectorPopover";
NSString *const XLFormRowDescriptorTypeSelectorLeftRight = @"selectorLeftRight";
// 三段选择
NSString *const XLFormRowDescriptorTypeSelectorSegmentedControl = @"selectorSegmentedControl";
// date 月 日 年 (内嵌)
NSString *const XLFormRowDescriptorTypeDateInline = @"dateInline";
// 日期picker选择器内嵌 dateTime更详细 星期 月 日 小时 分(内嵌)
NSString *const XLFormRowDescriptorTypeDateTimeInline = @"datetimeInline";
// date 小时 分 AM/PM(内嵌)
NSString *const XLFormRowDescriptorTypeTimeInline = @"timeInline";
// 计时器,选择hh mm(内嵌)
NSString *const XLFormRowDescriptorTypeCountDownTimerInline = @"countDownTimerInline";
// 月 日 年 sheet
NSString *const XLFormRowDescriptorTypeDate = @"date";
// 最详细的dateTime sheet
NSString *const XLFormRowDescriptorTypeDateTime = @"datetime";
// 小时 分 AM/PM sheet
NSString *const XLFormRowDescriptorTypeTime = @"time";
// 计时器 底部弹出来的
NSString *const XLFormRowDescriptorTypeCountDownTimer = @"countDownTimer";
// 直接展示一大坨datePicker
NSString *const XLFormRowDescriptorTypeDatePicker = @"datePicker";
NSString *const XLFormRowDescriptorTypePicker = @"picker";
// slider
NSString *const XLFormRowDescriptorTypeSlider = @"slider";
// 展示选中打钩的cell
NSString *const XLFormRowDescriptorTypeBooleanCheck = @"booleanCheck";
// 自带右边switch开关
NSString *const XLFormRowDescriptorTypeBooleanSwitch = @"booleanSwitch";
// button的cell 各种button位置需求
NSString *const XLFormRowDescriptorTypeButton = @"button";
// 简单的右侧描述信息的cell
NSString *const XLFormRowDescriptorTypeInfo = @"info";
// 展示segment count计数
NSString *const XLFormRowDescriptorTypeStepCounter = @"stepCounter";
你以为这就完了???!!!!
老外的库怎么能少了自定义功能呢,没有这个功能,那么这个库和咸鱼又有什么区别呢??!!
第一步:创建控制器(继承XLFormViewController)
分析:
这里init方法里面有三个值
XLFormDescriptor 表单
XLFormSectionDescriptor section
XLFormRowDescriptor row
咱们挨个创建,并且add到对应的section就可以了,最后记得带上一句self.form = form
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self)
{
[self initializeForm];
}
return self;
}
- (instancetype)init
{
self = [super init];
if (self) {
[self initializeForm];
}
return self;
}
// 初始化表单
- (void)initializeForm
{
// 表单对象
XLFormDescriptor *form;
// 表单Section对象
XLFormSectionDescriptor *section;
// 表单Row对象
XLFormRowDescriptor *row;
// 初始化form 顺便带个title
form = [XLFormDescriptor formDescriptorWithTitle:@"超级表单"];
// 第一个Section 没有参数的
section = [XLFormSectionDescriptor formSection];
[form addFormSection:section];
// 第一个就要自定义 车牌号 自定义cell
row = [XLFormRowDescriptor formRowDescriptorWithTag:@"first" rowType:XLFormRowDescriporTypeCar title:@"车牌号"];
row.required = YES;
row.value = @{@"country":@"浙",@"number":@"123456"};
[section addFormRow:row];
// 第二段
section = [XLFormSectionDescriptor formSection];
[form addFormSection:section];
// 第二个发动机号 自带的Cell
// Name
row = [XLFormRowDescriptor formRowDescriptorWithTag:@"second" rowType:XLFormRowDescriptorTypeText title:@"发动机号"];
row.required = YES;
// font
[row.cellConfig setObject:[UIFont boldSystemFontOfSize:16] forKey:@"textLabel.font"];
// font
[row.cellConfig setObject:[UIFont boldSystemFontOfSize:16] forKey:@"textField.font"];
// alignment
[row.cellConfig setObject:@(NSTextAlignmentRight) forKey:@"textField.textAlignment"];
[section addFormRow:row];
section = [XLFormSectionDescriptor formSection];
[form addFormSection:section];
// 第三个底部Sheet Picker 自带Cell
row = [XLFormRowDescriptor formRowDescriptorWithTag:@"third" rowType:XLFormRowDescriptorTypeSelectorPickerView title:@"车型"];
row.selectorOptions = @[[XLFormOptionsObject formOptionsObjectWithValue:@(0) displayText:@"奥迪A4"],
[XLFormOptionsObject formOptionsObjectWithValue:@(1) displayText:@"丰田SUV"],
[XLFormOptionsObject formOptionsObjectWithValue:@(2) displayText:@"凯迪拉克"],
[XLFormOptionsObject formOptionsObjectWithValue:@(3) displayText:@"奔驰"],
[XLFormOptionsObject formOptionsObjectWithValue:@(4) displayText:@"BMW"],
[XLFormOptionsObject formOptionsObjectWithValue:@(5) displayText:@"雷克萨斯"],
[XLFormOptionsObject formOptionsObjectWithValue:@(6) displayText:@"马自达"],
[XLFormOptionsObject formOptionsObjectWithValue:@(7) displayText:@"本田"],
[XLFormOptionsObject formOptionsObjectWithValue:@(8) displayText:@"特斯拉"],
[XLFormOptionsObject formOptionsObjectWithValue:@(9) displayText:@"福特"],
[XLFormOptionsObject formOptionsObjectWithValue:@(10) displayText:@"雷诺"],
[XLFormOptionsObject formOptionsObjectWithValue:@(11) displayText:@"法拉利"],
[XLFormOptionsObject formOptionsObjectWithValue:@(12) displayText:@"宾利"],
[XLFormOptionsObject formOptionsObjectWithValue:@(13) displayText:@"玛莎拉蒂"]
];
// row.value = [XLFormOptionsObject formOptionsObjectWithValue:@(3) displayText:@"Option 4"];
[section addFormRow:row];
// 第四个内嵌Picker 自带Cell
row = [XLFormRowDescriptor formRowDescriptorWithTag:@"four" rowType:XLFormRowDescriptorTypeSelectorPickerViewInline title:@"车长"];
row.selectorOptions = @[[XLFormOptionsObject formOptionsObjectWithValue:@(0) displayText:@"1M"],
[XLFormOptionsObject formOptionsObjectWithValue:@(1) displayText:@"2M"],
[XLFormOptionsObject formOptionsObjectWithValue:@(2) displayText:@"3M"],
[XLFormOptionsObject formOptionsObjectWithValue:@(3) displayText:@"4M"],
[XLFormOptionsObject formOptionsObjectWithValue:@(4) displayText:@"5M"],
[XLFormOptionsObject formOptionsObjectWithValue:@(5) displayText:@"6M"],
[XLFormOptionsObject formOptionsObjectWithValue:@(6) displayText:@"7M"],
[XLFormOptionsObject formOptionsObjectWithValue:@(7) displayText:@"8M"],
[XLFormOptionsObject formOptionsObjectWithValue:@(8) displayText:@"9M"],
[XLFormOptionsObject formOptionsObjectWithValue:@(9) displayText:@"10M"],
[XLFormOptionsObject formOptionsObjectWithValue:@(10) displayText:@"11M"],
[XLFormOptionsObject formOptionsObjectWithValue:@(11) displayText:@"12M"],
[XLFormOptionsObject formOptionsObjectWithValue:@(12) displayText:@"13M"],
[XLFormOptionsObject formOptionsObjectWithValue:@(13) displayText:@"14M"],
[XLFormOptionsObject formOptionsObjectWithValue:@(14) displayText:@"15M"],
];
[section addFormRow:row];
// 第五个浮动TF 自带cell
row = [XLFormRowDescriptor formRowDescriptorWithTag:@"five" rowType:XLFormRowDescriptorTypeFloatLabeledTextField111 title:@"请输入体积大小"];
[section addFormRow:row];
// 第六个测试下 自定义cell
row = [XLFormRowDescriptor formRowDescriptorWithTag:@"six" rowType:XLFormRowDescriporTypeFloat title:@"请输入面积大小"];
row.value = @{@"left":@"面积(m³)",@"right":@""};
[section addFormRow:row];
// 第七个评分 自带cell
row = [XLFormRowDescriptor formRowDescriptorWithTag:@"seven" rowType:XLFormRowDescriptorTypeRate title:@"First Rating"];
row.value = @(3);
[section addFormRow:row];
// 测试新增栏目 自带cell
section = [XLFormSectionDescriptor formSectionWithTitle:@"XLFormSectionInsertModeButton With Inline Cells"
sectionOptions:XLFormSectionOptionCanInsert
sectionInsertMode:XLFormSectionInsertModeButton];
[form addFormSection:section];
row = [XLFormRowDescriptor formRowDescriptorWithTag:nil rowType:XLFormRowDescriptorTypeDateInline];
row.value = [NSDate new];
row.title = @"新增picker栏测试";
section.multivaluedRowTemplate = row;
section = [XLFormSectionDescriptor formSection];
[form addFormSection:section];
row = [XLFormRowDescriptor formRowDescriptorWithTag:@"eight" rowType:XLFormRowDescriptorTypeUpload];
[section addFormRow:row];
self.form = form;
}
举个栗子(内嵌的pickerView)
row = [XLFormRowDescriptor formRowDescriptorWithTag:@"four" rowType:XLFormRowDescriptorTypeSelectorPickerViewInline title:@"车长"];
row.selectorOptions = @[[XLFormOptionsObject formOptionsObjectWithValue:@(0) displayText:@"1M"],
[XLFormOptionsObject formOptionsObjectWithValue:@(1) displayText:@"2M"],
[XLFormOptionsObject formOptionsObjectWithValue:@(2) displayText:@"3M"],
[XLFormOptionsObject formOptionsObjectWithValue:@(3) displayText:@"4M"],
[XLFormOptionsObject formOptionsObjectWithValue:@(4) displayText:@"5M"],
[XLFormOptionsObject formOptionsObjectWithValue:@(5) displayText:@"6M"],
[XLFormOptionsObject formOptionsObjectWithValue:@(6) displayText:@"7M"],
[XLFormOptionsObject formOptionsObjectWithValue:@(7) displayText:@"8M"],
[XLFormOptionsObject formOptionsObjectWithValue:@(8) displayText:@"9M"],
[XLFormOptionsObject formOptionsObjectWithValue:@(9) displayText:@"10M"],
[XLFormOptionsObject formOptionsObjectWithValue:@(10) displayText:@"11M"],
[XLFormOptionsObject formOptionsObjectWithValue:@(11) displayText:@"12M"],
[XLFormOptionsObject formOptionsObjectWithValue:@(12) displayText:@"13M"],
[XLFormOptionsObject formOptionsObjectWithValue:@(13) displayText:@"14M"],
[XLFormOptionsObject formOptionsObjectWithValue:@(14) displayText:@"15M"],
];
[section addFormRow:row];
非常的简单快速,初始化Row的时候第一个参数是该cell的identify值,方便后续点击事件的追溯,第二个参数就是
form表单中注册的一个ID,最后的title可有可无,用来初始化赋值,然后直接ADD到对应的section就可以了
第三步:自定义Cell到form表单中,有了它,你就能应付全世界的需求
再举个栗子....
我们介绍上面那栏,打分的不介绍了,需要的自己去下载Demo(文章结尾有地址)
其实在Controller中的代码还是一样简单
// 第六个测试下 自定义cell
row = [XLFormRowDescriptor formRowDescriptorWithTag:@"six" rowType:XLFormRowDescriporTypeFloat title:@"请输入面积大小"];
row.value = @{@"left":@"面积(m³)",@"right":@""};
[section addFormRow:row];
首先XIB来个cell(记得继承XLFormBaseCell,而且我们要放一个浮动的TextField进去)
自定义Cell我们必须重写三个方法
1.load (注册自定义cell)
2.configure (初始化配置)
3.update (更新数据其实就是更新rowDescription对象的Value字段,再VC里面代理刷新cell)
// 内部直接赋值
NSString * const XLFormRowDescriporTypeFloat = @"XLFormRowDescriporTypeFloat";
@interface MKJFloatTextFieldCell ()
@end
@implementation MKJFloatTextFieldCell
// 在主表单中注册对应的cell以及对应的ID
+(void)load
{
[XLFormViewController.cellClassesForRowDescriptorTypes setObject:NSStringFromClass([MKJFloatTextFieldCell class]) forKey:XLFormRowDescriporTypeFloat];
}
// 这个方法是用来设置属性的 必须重写 类似于初始化的属性不变的属性进行预先配置
- (void)configure
{
[super configure];
self.selectionStyle = UITableViewCellSelectionStyleNone;
self.leftLabel.layer.borderColor = [UIColor yellowColor].CGColor;
self.leftLabel.layer.borderWidth = 1.0f;
self.textField.delegate = self;
self.textField.font = [UIFont boldSystemFontOfSize:16];
self.textField.floatingLabel.font = [UIFont boldSystemFontOfSize:11];
self.textField.clearButtonMode = UITextFieldViewModeWhileEditing;
self.textField.floatingLabelTextColor = [UIColor lightGrayColor];
self.textField.floatingLabelActiveTextColor = [UIColor redColor];
}
// 这个方法是用来进行更新的,外面给唯一的字段Value设定值就好了 通过self.rowDescriptor.value的值变化来进行更新
- (void)update
{
[super update];
NSDictionary *value = self.rowDescriptor.value;
self.leftLabel.text = [value objectForKey:@"left"];
self.textField.text = [value objectForKey:@"right"];
self.textField.attributedPlaceholder =
[[NSAttributedString alloc] initWithString:self.rowDescriptor.title
attributes:@{NSForegroundColorAttributeName: [UIColor lightGrayColor]}];
self.textField.floatingLabel.text = @"快点输入面积大小";
}
整个表单的总数据是怎么来的
1.如何更新?(剩下的疑问看最后的几步)
这里XLFormRowDescription对象是有个id类型的value字段的,我们内部控件的事件更新了,我们只
负责更新都应的value字段(内部结构也是自己定义的数组或者字典或者其他)
- (void)textFieldDidEndEditing:(UITextField *)textField
{
[self textFieldDidChange:textField];
[self.formViewController textFieldDidEndEditing:textField];
}
#pragma mark - Helpers
- (void)textFieldDidChange:(UITextField *)textField
{
NSMutableDictionary *value = [self.rowDescriptor.value mutableCopy];
if (self.textField == textField) {
if ([self.textField.text length] > 0) {
[value setObject:self.textField.text forKey:@"right"];
} else {
[value setObject:@"" forKey:@"right"];
}
}
self.rowDescriptor.value = value;
}
这里已经更新了form表单中对应cell对应的value,但是这样貌似根本没有刷新嘛,像现
在这样的TextField就没事,如果和上图第一个cell那种的选择城市,需要更新cell,那
么,我们还需要在ViewController里面进行update一下
第四步:有些特定事件,需要在VC里面进行判断更新或者移除或者增加
// 每个cell内部的参数属性更改了就会调用这个方法,我们再次更新的话就会调用cell里面update的方法进行重绘
- (void)formRowDescriptorValueHasChanged:(XLFormRowDescriptor *)formRow oldValue:(id)oldValue newValue:(id)newValue
{
// 咱们这里统一调用更新
[super formRowDescriptorValueHasChanged:formRow oldValue:oldValue newValue:newValue];
[self updateFormRow:formRow];
// 以下就是一些典型的tag判断,根据不同的cell,remove 或 update进行更改
// if ([rowDescriptor.tag isEqualToString:@"first"]){
//
// }
// else if ([rowDescriptor.tag isEqualToString:@"second"]){
//
// [self updateFormRow:startDateDescriptor];
// [self updateFormRow:endDateDescriptor];
// }
// else if ([rowDescriptor.tag isEqualToString:@"third"]){
//
// [self updateFormRow:endDateDescriptor];
//
// }
// else if ([rowDescriptor.tag isEqualToString:@"这里填写的就是我们注册的ID"]){
//
// }
}
第五步:表单填完了,无论自定义还是自带的,都要搜集填写的
数据
XLFormViewController的代理方法
-(NSDictionary *)formValues;
有了它我们就能拿到所有的表单数据
- (IBAction)clickDone:(id)sender { NSDictionary *dict = [self formValues]; NSLog(@"表单中所有的字典值%@",dict); }
2016-09-09 14:23:54.403 MKJForm[3694:150388]表单中所有的字典值{
eight = "";
first = {
country = "\U5e7f";
number = "";
};
five = 2121212;
four = "";
second = 12121;
seven = 1;
six = {
left = "\U9762\U79ef(m\U00b3)";
right = 121212;
};
third = "";
}
- (void)dealloc
{
NSLog(@"%s-->dealloc",object_getClassName(self));
}
写完Demo,回头看确实非常方便,什么键盘高度,事件判断,tableView都不需要我们管理,关键是能自定义,一般有这个功能的组件都有点强的,用起来简直能飞
Demo地址:点击打开Demo链接
对了,看到这里的小伙伴,给大家分享个如何给Github上的README添加gif,我也是才
知道,赶紧记录下分享给大伙
点击打开链接(在末尾)