JYForm是一个强大的,能够灵活、动态创建和修改表单的iOS库
- ARC
- iOS 8.0+
- OC
JYForm
在创建时隐藏了复杂的实现,却可以依旧拥有强大,灵活的修改表单的能力。
我们使用三个类来定义一个表格:
- JYFormDescriptor
- JYFormSectionDescriptor
- JYFormRowDescriptor
一个表单即为一个JYFormDescriptor
对象,一个JYFormDescriptor
包含一个或者多个JYFormSectionDescriptor
对象,一个JYFormSectionDescriptor
对象包含一个或者多个JYFormRowDescriptor
对象。你可以注意到form的结构(JYFormDescriptor --> JYFormSectionDescriptor --> JYFormRowDescriptor)类似于UITableView
的结构(Table --> Sections --> Rows)。
让我们先看一个例子,看看如何使用JYForm创建一个表单:
- (void)viewDidLoad {
[super viewDidLoad];
JYFormDescriptor *formDescriptor = [JYFormDescriptor formDescriptor];
JYFormSectionDescriptor *section = nil;
JYFormRowDescriptor *row = nil;
section = [JYFormSectionDescriptor formSectionWithTitle:nil];
[formDescriptor addFormSection:section];
row = [JYFormRowDescriptor formRowDescriptorWithTag:@"00" rowType:JYFormRowDescriptorTypeFloatLabeledTextField title:@"姓名"];
[section addFormRow:row];
row.required = YES;
row = [JYFormRowDescriptor formRowDescriptorWithTag:@"01" rowType:JYFormRowDescriptorTypeFloatLabeledTextField title:@"身份证号"];
[section addFormRow:row];
row = [JYFormRowDescriptor formRowDescriptorWithTag:@"02" rowType:JYFormRowDescriptorTypeInteger title:@"手机号码"];
[section addFormRow:row];
row.required = YES;
section = [JYFormSectionDescriptor formSectionWithTitle:nil];
[formDescriptor addFormSection:section];
row = [JYFormRowDescriptor formRowDescriptorWithTag:@"10" rowType:JYFormRowDescriptorTypeText title:@"身份证地址"];
[section addFormRow:row];
row = [JYFormRowDescriptor formRowDescriptorWithTag:@"11" rowType:JYFormRowDescriptorTypeDate title:@"身份证有效期"];
[section addFormRow:row];
section = [JYFormSectionDescriptor formSectionWithTitle:nil];
[formDescriptor addFormSection:section];
row = [JYFormRowDescriptor formRowDescriptorWithTag:@"20" rowType:JYFormRowDescriptorTypeSelectorPush title:@"征信人类别"];
row.selectorOptions = [JYFormOptionsObject formOptionsObjectsWithValues:@[@1, @2, @3] displayTexts:@[@"主贷人", @"主贷人配偶", @"担保人"]];
row.selectorTitle = @"征信人类别";
[section addFormRow:row];
row = [JYFormRowDescriptor formRowDescriptorWithTag:@"21" rowType:JYFormRowDescriptorTypeSelectorPush title:@"贷款银行"];
row.selectorOptions = [JYFormOptionsObject formOptionsObjectsWithValues:@[@1, @2, @3] displayTexts:@[@"工行银行", @"农业银行", @"交通银行"]];
row.selectorTitle = @"贷款银行";
[section addFormRow:row];
section = [JYFormSectionDescriptor formSectionWithTitle:nil];
[formDescriptor addFormSection:section];
row = [JYFormRowDescriptor formRowDescriptorWithTag:@"30" rowType:JYFormRowDescriptorTypeInfo title:@"业务编号"];
row.value = @"1123131";
[section addFormRow:row];
JYForm *form = [[JYForm alloc] initWithFormDescriptor:formDescriptor autoLayoutSuperView:self。view];
[form beginLoading];
self。form = form;
}
在上面的代码中,当我们定义完form的主体结构,然后添加到父视图之后之后,可以调用-(void)beginLoading
来进行tableview的初始化操作。在后面如果我们想对form进行修改的话(删除添加行,删除添加节,修改行的内容),可以通过直接修改JYFormSectionDescriptor
、JYFormRowDescriptor
的方式。这样的好处是你可以不必再花时间在NSIndexPath
,UITableViewDelegate
、UITableViewDataSource
上了。
在上面那个例子中,在创建JYForm
对象的时候我是这样写的:
JYForm *form = [[JYForm alloc] initWithFormDescriptor:formDescriptor autoLayoutSuperView:self。view];
这样子可以将JYForm直接添加到self。view
中,并且自动使用NSLayout布局(JYForm与父视图在竖直与水平的间距均为0),当设备横向或者竖向时都能保持完全铺满父视图。如果需要更复杂点的自动布局,你可以需要自己实现了。。
JYForm *form1 = [[JYForm alloc] initWithFormDescriptor:formDescriptor];
[self。view addSubview:form1];
//自动布局代码。。。
你还可以使用CGRect对JYForm进行布局
JYForm *form = [[JYForm alloc] initWithFormDescriptor:formDescriptor frame:CGRectMake(0, 0, 375。, 667。)];
[self。view addSubview:form];
[form beginLoading];
这种方式比较简单,但有几个缺点:
- 就是设备横向与竖向时候,JYForm的显示可能会不一样。
- 键盘弹出时的动画可能会有点僵硬
NSString *const JYFormRowDescriptorTypeText = @"text";
这种样式下,UITextField
的autocapitalizationType
属性为UITextAutocapitalizationTypeSentences
(每句的首字母大写),autocorrectionType
属性为UITextAutocorrectionTypeDefault
,keyboardType
属性为UIKeyboardTypeDefault
NSString *const JYFormRowDescriptorTypeName = @"name";
这种样式下,UITextField
的autocapitalizationType
属性为UITextAutocapitalizationTypeWords
(每个词的首字母大写),autocorrectionType
属性为UITextAutocorrectionTypeNo
,keyboardType
属性为UIKeyboardTypeDefault
NSString *const JYFormRowDescriptorTypeURL = @"url";
这种样式下,UITextField
的autocapitalizationType
属性为UITextAutocapitalizationTypeNone
(无大写),autocorrectionType
属性为UITextAutocorrectionTypeNo
,keyboardType
属性为UIKeyboardTypeURL
NSString *const JYFormRowDescriptorTypeEmail = @"email";
这种样式下,UITextField
的autocapitalizationType
属性为UITextAutocapitalizationTypeNone
(无大写),autocorrectionType
属性为UITextAutocorrectionTypeNo
,keyboardType
属性为UIKeyboardTypeEmailAddress
NSString *const JYFormRowDescriptorTypePassword = @"password";
这种样式下,UITextField
的autocapitalizationType
属性为UITextAutocapitalizationTypeNone
(无大写),autocorrectionType
属性为UITextAutocorrectionTypeNo
,keyboardType
属性为UIKeyboardTypeASCIICapable
,并且secureTextEntry
属性为YES
NSString *const JYFormRowDescriptorTypeNumber = @"number";
这种样式下,UITextField
的autocapitalizationType
属性为UITextAutocapitalizationTypeNone
(无大写),autocorrectionType
属性为UITextAutocorrectionTypeNo
,keyboardType
属性为UIKeyboardTypeNumbersAndPunctuation
NSString *const JYFormRowDescriptorTypeInteger = @"integer";
这种样式下,UITextField
的autocapitalizationType
属性为UITextAutocapitalizationTypeNone
(无大写),autocorrectionType
属性为UITextAutocorrectionTypeNo
,keyboardType
属性为UIKeyboardTypeNumberPad
NSString *const JYFormRowDescriptorTypeDecimal = @"decimal";
这种样式下,UITextField
的autocapitalizationType
属性为UITextAutocapitalizationTypeNone
(无大写),autocorrectionType
属性为UITextAutocorrectionTypeNo
,keyboardType
属性为UIKeyboardTypeDecimalPad
NSString *const JYFormRowDescriptorTypePhone = @"phone";
这种样式下,UITextField
的autocapitalizationType
属性为UITextAutocapitalizationTypeNone
(无大写),autocorrectionType
属性为UITextAutocorrectionTypeNo
,keyboardType
属性为UIKeyboardTypeNumberPad
NSString *const JYFormRowDescriptorTypeTextView = @"textView";
这种样式下,UITextField
的autocapitalizationType
属性为UITextAutocapitalizationTypeSentences
(每句的首字母大写),autocorrectionType
属性为UITextAutocorrectionTypeNo
,keyboardType
属性为UIKeyboardTypeDefault
选择行允许我们从某个选择列表中选择一行或者几行
NSString *const JYFormRowDescriptorTypeSelectorPush = @"selectorPush";
NSString *const JYFormRowDescriptorTypeMultipleSelector = @"multipleSelector";
NSString *const JYFormRowDescriptorTypeSelectorActionSheet = @"selectorActionSheet";
NSString *const JYFormRowDescriptorTypeSelectorAlertView = @"selectorAlertView";
NSString *const JYFormRowDescriptorTypeSelectorPickerView = @"selectorPickerView";
单个选择项必须为JYFormOptionsObject
对象(JYFormRowDescriptorTypeSelectorPush,JYFormRowDescriptorTypeMultipleSelector可能除外),JYFormOptionsObject
有两个属性formDisplaytext
(文本显示),formValue
(实际值)。你需要将你想要添加的一些选择项添加到JYFormRowDescriptor
的selectorOptions
属性。
JYForm遵循下列的先后顺序来显示您的选择项文本:
- 如果
JYFormRowDescriptor
的valueTransformer
属性不为空,则会显示valueTransformer
转换JYFormOptionsObject
的formDisplaytext
之后的文本。 - 直接显示
JYFormOptionsObject
的formDisplaytext
文本
NSString *const JYFormRowDescriptorTypeDate = @"date";
NSString *const JYFormRowDescriptorTypeTime = @"time";
NSString *const JYFormRowDescriptorTypeDateTime = @"datetime";
NSString *const JYFormRowDescriptorTypeCountDownTimer = @"countDownTimer";
NSString *const JYFormRowDescriptorTypeDateInline = @"dateInline";
NSString *const JYFormRowDescriptorTypeSwitch = @"switch";
NSString *const JYFormRowDescriptorTypeCheck = @"check";
NSString *const JYFormRowDescriptorTypeStepCounter = @"stepCounter";
你可以这样设置它
[row.cellConfigAtConfigure setObject:@YES forKey:@"stepControl。wraps"];
[row.cellConfigAtConfigure setObject:@10 forKey:@"stepControl。stepValue"];
[row.cellConfigAtConfigure setObject:@10 forKey:@"stepControl。minimumValue"];
[row.cellConfigAtConfigure setObject:@100 forKey:@"stepControl。maximumValue"];
NSString *const JYFormRowDescriptorTypeSlider = @"slider";
你可以这样设置它:
[row.cellConfigAtConfigure setObject:@(100) forKey:@"slider。maximumValue"];
[row.cellConfigAtConfigure setObject:@(10) forKey:@"slider。minimumValue"];
[row.cellConfigAtConfigure setObject:@(4) forKey:@"steps"];
NSString *const JYFormRowDescriptorTypeInfo = @"info";
有时候我们需要一些不可编辑的行来展示一些信息(例如版本信息),JYForm提供了我们JYFormRowDescriptorTypeInfo
的行类型来展示不可编辑的信息。
NSString *const JYFormRowDescriptorTypeButton = @"button";
按钮行允许我们再选中行的时候执行一些操作,他按照下面的规则来响应事件
- 如果
JYFormRowDescriptor
的action
的rowBlock
不为空,则执行block - 如果
JYFormRowDescriptor
的action
的viewControllerClass
不为空,则跳转到该视图控制器
如果在JYForm中需要删除行,那你需要这样子初始化JYFormSectionDescriptor
对象
section = [JYFormSectionDescriptor formSectionWithTitle:@"Delete" sectionOptions:JYFormSectionOptionCanDelete];
[formDescriptor addFormSection:section];
当JYForm
的tableView
的editing
属性为YES是,样式如下
如果tableView
的editing
属性为NO,那么你可以通过左滑来删除行,效果如下
你可以通过获取到表单上每行的值通过调用JYForm
的- (NSDictionary *)formValues;
方法或者JYFormDescriptor
的- (NSDictionary *)formValues;
方法。
结果NSDictionary
的创建规则如下
- 遍历每一行,如果这行的
tag
的不为空,则以改行的tag
为key,该行的value(value为空时传[NSNull null])为value添加到字典中。 - 需要注意如果该行是选中选择行类型的话,那么该行的value为
JYFormOptionsObject
对象,或者NSArray<JYFormOptionsObject *>
类型
当我们创建好表单之后,常常需要将表单各行的值通过请求发送给后台,在这个时候你可以试着调用JYForm
的- (NSDictionary *)httpParameters;
方法或者JYFormDescriptor
的- (NSDictionary *)httpParameters:(JYForm *)form
方法来获取httpParameters
。
结果NSDictionary
的创建规则如下
- 如果改行实现了代理
JYFormDescriptorCell
的方法- (NSString *)formDescriptorHttpParameterName;
,则以该返回值为key,改行的值为value(value为空时传[NSNull null])添加到字典中,如果没有实现该方法且tag
不为空,则以tag
为key,行的值为value添加到字典中 - 如果改行的值为
JYFormOptionsObject
对象,则添加的是JYFormOptionsObject
的formValue
属性;如果该行的值为如果改行的值为NSArray<JYFormOptionsObject *>
类型 ,则添加到字典的值为NSArray<JYFormOptionsObject。formValue>
;如果该行的值为NSString
,NSNumber
,NSDate
类型,则返回该值本身
如果你想要创建自己的UITableViewCell
的话,那么一定要继承JYFormBaseCell
。JYFormBaseCell
必须要实现JYFormDescriptorCell
代理。
@protocol JYFormDescriptorCell <NSObject>
@required
/**
初始化控件以及一些数据,在cell被创建时会被调用,只被调用一次
*/
- (void)configure;
/**
更新cell的控件,能被多次调用
*/
- (void)update;
@optional
/**
如果你没有指定JYFormRowDescriptor的height属性,并且这个方法被实现了,那么cell的高度为这个方法的返回值。
@param rowDescriptor JYFormRowDescriptor的实例
@return JYFormRowDescriptor对应的cell的高度
*/
+ (CGFloat)formDescriptorCellHeightForRowDescriptor:(JYFormRowDescriptor *)rowDescriptor;
/**
返回一个bool值,指示cell能够成为第一响应者,默认返回NO
@return 如果cell可以成为第一响应者的话返回YES,否则返回NO
*/
- (BOOL)formDescriptorCellCanBecomeFirstResponder;
/**
让当前的cell成为第一响应者
@return 如果cell是第一响应者了返回YES,否则返回NO
*/
- (BOOL)formDescriptorCellBecomeFirstResponder;
/**
当前的cell被选中了
@param form cell被添加到的JYForm的实例
*/
- (void)formDescriptorCellDidSelectedWithForm:(JYForm *)form;
/**
为该cell设置一个HttpParameterName,那么当调用JYFormDescriptor的实例方法-(void)httpParameters时,则会将该行,以方法返回值为key,值为value添加到结果字典中
@return 为该cell设置一个HttpParameterName,不能为空
*/
- (NSString *)formDescriptorHttpParameterName;
/**
当cell成为第一响应者时被调用,可以通过该方法改变cell的样式
*/
-(void)highlight;
/**
当cell退出第一响应者时被调用
*/
-(void)unhighlight;
@end
当你创建好了一个新类JYFormTestCell
,那么你在实现完代理方法之后,在@implementation
后面的将类添加到JYForm的cellClassesForRowDescriptorTypes
中,代码如下
+ (void)load
{
[JYForm。cellClassesForRowDescriptorTypes setObject:[JYFormTestCell class] forKey:@"Test"];
}
添加完成之后,你可以直接在JYForm中直接添加这种类型的行JYFormRowDescriptor *row = [JYFormRowDescriptor formRowDescriptorWithTag:@"test" rowType:@"Test"]
对JYFormDescriptor
做的修改都会映射在JYForm中的'tableView'上,例如你对JYFormSectionDescriptor
和JYFormRowDescriptor
进行添加和删除,会直接表现在section以及row的添加或者删除。
也就是说,在JYForm中,我们再也不用使用NSIndexPath
进行UITableViewCell
的添加和删除。在JYForm中,每个JYFormRowDescriptor
都有tag
属性,我们可以通过JYFormDescriptor
查找tag
的方式来找到JYFormRowDescriptor
,通过tag
管理JYFormRowDescriptor
显然会容易的多,类似于JS。因此,每个JYFormRowDescriptor
的tag
必须是唯一的。
通常来说,直接修改UITableView的样式是不被允许的,你可以通过修改JYFormDescriptor
,JYFormSectionDescriptor
,JYFormRowDescriptor
来修改UITableView
。
JYFormDescriptor
和JYFormSectionDescriptor
均有hidden
属性,你可以将其设置为YES,来达到隐藏的目的。
JYFormDescriptor
和JYFormSectionDescriptor
均有disable
属性,你可以将其设置为YES,来达到隐藏的目的。禁用时,row会处于不可编辑状态,只能显示信息,不能响应事件。
JYForm允许你定义两个row的依赖关系,当一行的值发生改变时另一行产生响应的变化,代码如下:
- (void)viewDidLoad {
[super viewDidLoad];
JYFormDescriptor *formDescriptor = [JYFormDescriptor formDescriptor];
JYFormSectionDescriptor *section = nil;
JYFormRowDescriptor *row = nil;
//第一段
section = [JYFormSectionDescriptor formSectionWithTitle:@"第一行"];
[formDescriptor addFormSection:section];
row = [JYFormRowDescriptor formRowDescriptorWithTag:@"00" rowType:JYFormRowDescriptorTypeSwitch title:@"显示下一行"];
row.onChangeBlock = ^(id oldValue, id newValue, JYFormRowDescriptor *rowDescriptor) {
JYFormRowDescriptor *nextRow = [formDescriptor formRowWithTag:@"01"];
if ([newValue boolValue]) {
nextrow.hidden = NO;
} else {
nextrow.hidden = YES;
}
};
[section addFormRow:row];
row = [JYFormRowDescriptor formRowDescriptorWithTag:@"01" rowType:JYFormRowDescriptorTypeSwitch title:@"显示下一节"];
row.onChangeBlock = ^(id oldValue, id newValue, JYFormRowDescriptor *rowDescriptor) {
if ([newValue boolValue]) {
self。nextSection。hidden = NO;
} else {
self。nextSection。hidden = YES;
}
};
[section addFormRow:row];
row.hidden = YES;
//第二段
section = [JYFormSectionDescriptor formSectionWithTitle:@"依赖的section"];
[formDescriptor addFormSection:section];
section。hidden = YES;
self。nextSection = section;
row = [JYFormRowDescriptor formRowDescriptorWithTag:@"10" rowType:JYFormRowDescriptorTypeName];
[row.cellConfigAtConfigure setObject:@"这是第二节" forKey:@"textField。placeholder"];
[row.cellConfigAtConfigure setObject:@(NSTextAlignmentLeft) forKey:@"textField。textAlignment"];
[section addFormRow:row];
JYForm *form = [[JYForm alloc] initWithFormDescriptor:formDescriptor autoLayoutSuperView:self。view];
[form beginLoading];
self。form = form;
// Do any additional setup after loading the view。
}
JYForm提供验证功能,验证该行的值是否符合我们设定的条件。
每一个JYFormRowDescriptor
都可以有一个列表的验证器。通过下面的三个方法,我们可以添加,或者删除验证器,或者对该行进行验证。
- (void)addValidator:(nonnull id<JYFormValidatorProtocol>)validator;
- (void)removeValidator:(nonnull id<JYFormValidatorProtocol>)validator;
- (nullable JYFormValidationObject *)doValidation;
当JYFormRowDescriptor
进行了验证doValidation
,如果结果不通过,会返回一个JYFormValidationObject
实例,该对象里面有错误信息,以及所关联的JYFormRowDescriptor
实例
。
我们可以创建自己的验证器,只需要实现JYFormValidatorProtocol
代理。
@protocol JYFormValidatorProtocol <NSObject>
@required
- (JYFormValidationObject *)isValid:(JYFormRowDescriptor *)row;
@end
JYFormRegexValidator
是JYForm创建的一个验证器,通过该类,你可以学习到一个验证器该如何工作。
当JYFormRowDescriptor
的required
属性为YES是,那么如果改行值为空的话也是通过不了验证的。
你可以通过JYform
的- (NSArray *)formValidationErrors;
方法所有验证不通过的行的错误信息。
JYFormRowDescriptor
允许我们对UITableViewCell
进行一般的配置,例如rowType
,value
,改行是否required
,hidden
,disabled
等
当然,我们还可以使用KVC的方式对UITableViewCell
的其他属性进行设置。JYFormRowDescriptor
提供了四个配置字典供用户在不同的地方,时间段对UITableViewCell
进行配置
///|< 配置cell,当JYForm调用update方法后使用
@property (nonnull, nonatomic, strong, readonly) NSMutableDictionary *cellConfigAfterUpdate;
///|< 配置cell,在JYFormOptionsViewController中的cellForRowAtIndexPath方法中被使用
@property (nonnull, nonatomic, strong, readonly) NSMutableDictionary *cellConfigForSelector;
///|< 配置cell,当JYForm调用update方法后,且disable属性为Yes时被使用
@property (nonnull, nonatomic, strong, readonly) NSMutableDictionary *cellConfigIfDisabled;
///|< 配置cell,当cell调用config之后,update方法之前调用
@property (nonnull, nonatomic, strong, readonly) NSMutableDictionary *cellConfigAtConfigure;
你可以像下面这样进行配置:
row = [JYFormRowDescriptor formRowDescriptorWithTag:@"name" rowType:JYFormRowDescriptorTypeText];
[row.cellConfigAtConfigure setObject:@"姓名" forKey:@"textField。placeholder"];
[row.cellConfigAtConfigure setObject:@(NSTextAlignmentLeft) forKey:@"textField。textAlignment"];
[row.cellConfigAtConfigure setObject:[UIColor redColor] forKey:@"textField。placeholderLabel。textColor"];
[section addFormRow:row];
你也可以通过设置JYFormSectionDescriptor
的headerHieght
和headerView
或者footerHieght
和footerView
属性来自定义header/footer
你可以设置row的属性value
@property (nullable, nonatomic, strong) id value;
你可以发现这个属性的类型是id
,所以你设置value时需要注意值的类型。例如,JYFormRowDescriptorTypeDate
的类型为NSDate
,JYFormRowDescriptorTypeText
的类型为NSString
。当设置完成之后,如果你需要刷新row的UI,你可以调用JYForm
的方法- (void)reloadFormRow:(JYFormRowDescriptor *)formRow;
JYForm有若干的选择行类型,大部分的类型都必须要先知道选项(如果设置了action
的viewControllerClass
属性,JYFormRowDescriptorTypeSelectorPush,JYFormRowDescriptorTypeMultipleSelector不需要)。你可以通过设置JYFormRowDescriptor
的selectorOptions
属性来设置选项。
具体可以再看一眼上面的内容: 获取表单值
你可以通过下面的代码这样设置
//设置范围0 ~ 1。0f
[row.cellConfigAtConfigure setObject:[NSNumber numberWithFloat:0。7] forKey:XLFormTextFieldLengthPercentage];
[row.cellConfigAtConfigure setObject:@(20) forKey:@"textViewMaxNumberOfCharacters"];
[row.cellConfigAtConfigure setObject:@(UIReturnKeyGo) forKey:@"nextReturnKeyType"];
可以在JYFormAppearanceConfig.h文件中,设置下面两个属性:
///|< cell主标题的字体
#define kJYForm_Cell_MainTextFont [UIFont preferredFontForTextStyle:UIFontTextStyleBody]
///|< cell副标题的字体
#define kJYForm_Cell_DetailTextFont [UIFont preferredFontForTextStyle:UIFontTextStyleBody]
可以在JYFormAppearanceConfig.h文件中,设置下面几个属性:
///|< cell主标题颜色
#define kJYForm_Cell_MainTextColor UIColorHex(333333)
///|< cell被禁用时主标题颜色
#define kJYForm_Cell_MainDisableTextColor UIColorHex(a4a4a4)
///|< cell副标题的颜色
#define kJYForm_Cell_DetailTextColor UIColorHex(464646)
///|< cell被禁用时副标题的颜色
#define kJYForm_Cell_DetailDisableTextColor UIColorHex(c8c8c8)
你可以通过下面的代码这样设置
[row.cellConfigAtConfigure setObject:[NSDate new] forKey:@"minimumDate"];
[row.cellConfigAtConfigure setObject:[NSDate dateWithTimeIntervalSinceNow:(60*60*24*3)] forKey:@"maximumDate"];
form。disable = YES;
[form。tableView reloadData];
cell的高度优先级按照以下规则
- 指定JYFormRowDescriptor的
height
属性 - 实现
JYFormDescriptorCell
代理的方法+ (CGFloat)formDescriptorCellHeightForRowDescriptor:(JYFormRowDescriptor *)rowDescriptor;
- 前两部都没有的吗,则返回默认高度
static const CGFloat kCellestimatedRowHeight = 55。0;