Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

XLForm is the most flexible and powerful iOS library to create dynamic table-view forms. Fully compatible with Swift & Obj-C.

License

NotificationsYou must be signed in to change notification settings

xmartlabs/XLForm

Repository files navigation

XLForm

Build StatusCocoaPods compatible

If you are working in Swift then you should have a look atEureka, a complete re-design of XLForm in Swift and with more features.

We are not implementing any new features for XLForm anymore. However, if a critical issue arises we will fix it.

Purpose

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 but spending 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.

Let's see the iOS Calendar Event Form created using XLForm

Screenshot of native Calendar Event Example

What XLForm does

  • Loads a form based on a declarativeform definition.
  • Keeps track of definition changes on runtime to update the form interface accordingly. Further information onDynamic Forms section of this readme.
  • Supports multivalued sections allowing us to create, delete or reorder rows. For further details seeMultivalued Sections section bellow.
  • Supportscustom rows definition.
  • Supports custom selectors. For further details of how to define your own selectors checkCustom selectors section out.
  • Provides several inline selectors such as date picker and picker inline selectors and brings a way to create custom inline selectors.
  • Form data validation based on form definition.
  • Ability to easily navigate among rows, fully customizable.
  • Ability to show inputAccessoryView if needed. By default a navigation input accessory view is shown.
  • Read only mode for a particular row or the entire form.
  • Rows can be hidden or shown depending on other rows values. This can be done declaratively usingNSPredicates. (seeMake a row or section invisible depending on other rows values)

How to create a form

Create an instance of XLFormViewController

Swift
classCalendarEventFormViewController:XLFormViewController{requiredinit(coder aDecoder:NSCoder){    super.init(coder: aDecoder)self.initializeForm()}overrideinit(nibName nibNameOrNil:String?, bundle nibBundleOrNil:NSBundle?){    super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)self.initializeForm()}func initializeForm(){    // Implementation details covered in the next section.}}
Objective-C
#import"XLFormViewController.h"@interfaceCalendarEventFormViewController:XLFormViewController@end
@interfaceExamplesFormViewController ()@end@implementationExamplesFormViewController- (instancetype)initWithNibName:(NSString *)nibNameOrNilbundle:(NSBundle *)nibBundleOrNil {    self = [superinitWithNibName:nibNameOrNilbundle:nibBundleOrNil];if (self){        [selfinitializeForm];    }return self;}- (id)initWithCoder:(NSCoder *)aDecoder {    self = [superinitWithCoder:aDecoder];if (self){        [selfinitializeForm];    }return self;}- (void)initializeForm {// Implementation details covered in the next section.}@end
Implementing the initializeForm method

To create a form we should declare it through aXLFormDescriptor instance and assign it to aXLFormViewController instance. As we said XLForm works based on a DSL that hides complex and boilerplate stuff without losing the power and flexibility of hand-made forms.

To define a form we use 3 classes:

  • XLFormDescriptor
  • XLFormSectionDescriptor
  • XLFormRowDescriptor

A form definition is aXLFormDescriptor instance that contains one or more sections (XLFormSectionDescriptor instances) and each section contains several rows (XLFormRowDescriptor instance). As you may have noticed the DSL structure is analog to the structure of aUITableView (Table -->> Sections -- >> Rows). The resulting table-view form's structure (sections and rows order) mirrors the definition's structure.

Let's see an example implementation of initializeForm to define the iOS Calendar Event Form
- (void)initializeForm {  XLFormDescriptor * form;  XLFormSectionDescriptor * section;  XLFormRowDescriptor * row;  form = [XLFormDescriptorformDescriptorWithTitle:@"Add Event"];// First section  section = [XLFormSectionDescriptorformSection];  [formaddFormSection:section];// Title  row = [XLFormRowDescriptorformRowDescriptorWithTag:@"title"rowType:XLFormRowDescriptorTypeText];  [row.cellConfigAtConfiguresetObject:@"Title"forKey:@"textField.placeholder"];  [sectionaddFormRow:row];// Location  row = [XLFormRowDescriptorformRowDescriptorWithTag:@"location"rowType:XLFormRowDescriptorTypeText];  [row.cellConfigAtConfiguresetObject:@"Location"forKey:@"textField.placeholder"];  [sectionaddFormRow:row];// Second Section  section = [XLFormSectionDescriptorformSection];  [formaddFormSection:section];// All-day  row = [XLFormRowDescriptorformRowDescriptorWithTag:@"all-day"rowType:XLFormRowDescriptorTypeBooleanSwitchtitle:@"All-day"];  [sectionaddFormRow:row];// Starts  row = [XLFormRowDescriptorformRowDescriptorWithTag:@"starts"rowType:XLFormRowDescriptorTypeDateTimeInlinetitle:@"Starts"];  row.value = [NSDatedateWithTimeIntervalSinceNow:60*60*24];  [sectionaddFormRow:row];  self.form = form;}

XLForm will load the table-view form from the previously explained definition. The most interesting part is that it will update the table-view form based on the form definition modifications.That means that we are able to make changes on the table-view form adding or removing section definitions or row definitions to the form definition on runtime and you will never need to care again aboutNSIndexPath,UITableViewDelegate,UITableViewDataSource or other complexities.

To see more complex form definitions take a look at the example application in the Examples folder of this repository. You can also run the examples on your own device if you wish. XLFormhas no dependencies over other pods, anyway the examples project makes use of some cocoapods to show advanced XLForm features.

Using XLForm with Storyboards

  • Perform the steps fromHow to create a form
  • In Interface Builder (IB), drag-and-drop aUIViewController onto the Storyboard
  • Associate your custom form class to theUIViewController using theIdentity Inspector

How to run XLForm examples

  1. Clone the repositorygit@github.com:xmartlabs/XLForm.git. Optionally you can fork the repository and clone it from your own github account, this approach would be better in case you want to contribute.
  2. Move to either the Objective-c or Swiftexample folder.
  3. Install example project cocoapod dependencies. From inside Objective-c or Swift example folder runpod install.
  4. Open XLForm or SwiftExample workspace using XCode and run the project. Enjoy!

Rows

Input Rows

Screenshot of Input Examples

Input rows allows the user to enter text values. Basically they useUITextField orUITextView controls. The main differences among the input row types is thekeyboardType,autocorrectionType andautocapitalizationType configuration.

staticNSString *const XLFormRowDescriptorTypeText =@"text";

Will be represented by aUITextField withUITextAutocorrectionTypeDefault,UITextAutocapitalizationTypeSentences andUIKeyboardTypeDefault.

staticNSString *const XLFormRowDescriptorTypeName =@"name";

Will be represented by aUITextField withUITextAutocorrectionTypeNo,UITextAutocapitalizationTypeWords andUIKeyboardTypeDefault.

staticNSString *const XLFormRowDescriptorTypeURL =@"url";

Will be represented by aUITextField withUITextAutocorrectionTypeNo,UITextAutocapitalizationTypeNone andUIKeyboardTypeURL.

staticNSString *const XLFormRowDescriptorTypeEmail =@"email";

Will be represented by aUITextField withUITextAutocorrectionTypeNo,UITextAutocapitalizationTypeNone andUIKeyboardTypeEmailAddress.

staticNSString *const XLFormRowDescriptorTypePassword =@"password";

Will be represented by aUITextField withUITextAutocorrectionTypeNo,UITextAutocapitalizationTypeNone andUIKeyboardTypeASCIICapable.This row type also set thesecureTextEntry toYES in order to hide what the user types.

staticNSString *const XLFormRowDescriptorTypeNumber =@"number";

Will be represented by aUITextField withUITextAutocorrectionTypeNo,UITextAutocapitalizationTypeNone andUIKeyboardTypeNumbersAndPunctuation.

staticNSString *const XLFormRowDescriptorTypePhone =@"phone";

Will be represented by aUITextField withUIKeyboardTypePhonePad.

staticNSString *const XLFormRowDescriptorTypeTwitter =@"twitter";

Will be represented by aUITextField withUITextAutocorrectionTypeNo,UITextAutocapitalizationTypeNone andUIKeyboardTypeTwitter.

staticNSString *const XLFormRowDescriptorTypeAccount =@"account";

Will be represented by aUITextField withUITextAutocorrectionTypeNo,UITextAutocapitalizationTypeNone andUIKeyboardTypeDefault.

staticNSString *const XLFormRowDescriptorTypeInteger =@"integer";

Will be represented by aUITextField withUIKeyboardTypeNumberPad.

staticNSString *const XLFormRowDescriptorTypeDecimal =@"decimal";

Will be represented by aUITextField withUIKeyboardTypeDecimalPad.

staticNSString *const XLFormRowDescriptorTypeTextView =@"textView";

Will be represented by aUITextView withUITextAutocorrectionTypeDefault,UITextAutocapitalizationTypeSentences andUIKeyboardTypeDefault.

Selector Rows

Selector rows allow us to select a value or values from a list. XLForm supports 8 types of selectors out of the box:

Screenshot of native Calendar Event Example

staticNSString *const XLFormRowDescriptorTypeSelectorPush =@"selectorPush";
staticNSString *const XLFormRowDescriptorTypeSelectorActionSheet =@"selectorActionSheet";
staticNSString *const XLFormRowDescriptorTypeSelectorAlertView =@"selectorAlertView";
staticNSString *const XLFormRowDescriptorTypeSelectorLeftRight =@"selectorLeftRight";
staticNSString *const XLFormRowDescriptorTypeSelectorPickerView =@"selectorPickerView";
staticNSString *const XLFormRowDescriptorTypeSelectorPickerViewInline =@"selectorPickerViewInline";
staticNSString *const XLFormRowDescriptorTypeSelectorSegmentedControl =@"selectorSegmentedControl";
staticNSString *const XLFormRowDescriptorTypeMultipleSelector =@"multipleSelector";

Normally we will have a collection of object to select (these objects should have a string to display them and a value in order to serialize them), XLForm has to be able to display these objects.

XLForm follows the following rules to display an object:

  1. If the value of theXLFormRowDescriptor object is nil, XLForm uses thenoValueDisplayText row property as display text.
  2. If the XLFormRowDescriptor instance has avalueTransformer property value. XLForm uses theNSValueTransformer to convert the selected object to a NSString.
  3. If the object is aNSString orNSNumber it uses the objectdescription property.
  4. If the object conforms to protocolXLFormOptionObject, XLForm gets the display value fromformDisplayText method.
  5. Otherwise it return nil. That means you should conforms the protocol:).

You may be interested in change the display text either by setting upnoValueDisplayText orvalueTransformer property or making the selector options objects to conform toXLFormOptionObject protocol.

This is the protocol declaration:

@protocolXLFormOptionObject <NSObject>@required-(NSString *)formDisplayText;-(id)formValue;@end

Date & Time Rows

XLForms supports 3 types of dates:Date,DateTime ,Time andCountdown Timer and it's able to present theUIDatePicker control in 2 different ways, inline and non-inline.

Screenshot of native Calendar Event Example

staticNSString *const XLFormRowDescriptorTypeDateInline =@"dateInline";
staticNSString *const XLFormRowDescriptorTypeDateTimeInline =@"datetimeInline";
staticNSString *const XLFormRowDescriptorTypeTimeInline =@"timeInline";
staticNSString *const XLFormRowDescriptorTypeCountDownTimerInline =@"countDownTimerInline";
staticNSString *const XLFormRowDescriptorTypeDate =@"date";
staticNSString *const XLFormRowDescriptorTypeDateTime =@"datetime";
staticNSString *const XLFormRowDescriptorTypeTime =@"time";
staticNSString *const XLFormRowDescriptorTypeCountDownTimer =@"countDownTimer";

Here is an example of how to define these row types:

Objective C

XLFormDescriptor * form;XLFormSectionDescriptor * section;XLFormRowDescriptor * row;form = [XLFormDescriptorformDescriptorWithTitle:@"Dates"];section = [XLFormSectionDescriptorformSectionWithTitle:@"Inline Dates"];[formaddFormSection:section];// Daterow = [XLFormRowDescriptorformRowDescriptorWithTag:kDateInlinerowType:XLFormRowDescriptorTypeDateInlinetitle:@"Date"];row.value = [NSDatenew];[sectionaddFormRow:row];// Timerow = [XLFormRowDescriptorformRowDescriptorWithTag:kTimeInlinerowType:XLFormRowDescriptorTypeTimeInlinetitle:@"Time"];row.value = [NSDatenew];[sectionaddFormRow:row];// DateTimerow = [XLFormRowDescriptorformRowDescriptorWithTag:kDateTimeInlinerowType:XLFormRowDescriptorTypeDateTimeInlinetitle:@"Date Time"];row.value = [NSDatenew];[sectionaddFormRow:row];// CountDownTimerrow = [XLFormRowDescriptorformRowDescriptorWithTag:kCountDownTimerInlinerowType:XLFormRowDescriptorTypeCountDownTimerInlinetitle:@"Countdown Timer"];row.value = [NSDatenew];[sectionaddFormRow:row];

Swift

staticletdateTime="dateTime"staticletdate="date"staticlettime="time"varform:XLFormDescriptorvarsection:XLFormSectionDescriptorvarrow:XLFormRowDescriptorform=XLFormDescriptor(title:"Dates")asXLFormDescriptorsection=XLFormSectionDescriptor.formSectionWithTitle("Inline Dates")asXLFormSectionDescriptorform.addFormSection(section)// Daterow=XLFormRowDescriptor(tag: tag.date, rowType: XLFormRowDescriptorTypeDateInline, title:"Date")row.value=NSDate()section.addFormRow(row)// Timerow=XLFormRowDescriptor(tag: tag.time, rowType: XLFormRowDescriptorTypeTimeInline, title:"Time")row.value=NSDate()section.addFormRow(row)// DateTimerow=XLFormRowDescriptor(tag: tag.dateTime, rowType: XLFormRowDescriptorTypeDateTimeInline, title:"Date Time")row.value=NSDate()section.addFormRow(row)self.form= form;

Boolean Rows

XLForms supports 2 types of boolean controls:

Screenshot of native Calendar Event Example

staticNSString *const XLFormRowDescriptorTypeBooleanCheck =@"booleanCheck";
staticNSString *const XLFormRowDescriptorTypeBooleanSwitch =@"booleanSwitch";

We can also simulate other types of Boolean rows using any of the Selector Row Types introduced in theSelector Rows section.

Other Rows

Stepper

XLForms supports counting using UIStepper control:

Screenshot of native Calendar Event Example

staticNSString *const XLFormRowDescriptorTypeStepCounter =@"stepCounter";

You can set the stepper paramaters easily:

row = [XLFormRowDescriptorformRowDescriptorWithTag:kStepCounterrowType:XLFormRowDescriptorTypeStepCountertitle:@"Step counter"];row.value = @50;[row.cellConfigAtConfiguresetObject:@YESforKey:@"stepControl.wraps"];[row.cellConfigAtConfiguresetObject:@10forKey:@"stepControl.stepValue"];[row.cellConfigAtConfiguresetObject:@10forKey:@"stepControl.minimumValue"];[row.cellConfigAtConfiguresetObject:@100forKey:@"stepControl.maximumValue"];
Slider

XLForms supports counting using UISlider control:

staticNSString *const XLFormRowDescriptorTypeSlider =@"slider";

You can adjust the slider for your own interests very easily:

row = [XLFormRowDescriptorformRowDescriptorWithTag:kSliderrowType:XLFormRowDescriptorTypeSlidertitle:@"Slider"];row.value = @(30);[row.cellConfigAtConfiguresetObject:@(100)forKey:@"slider.maximumValue"];[row.cellConfigAtConfiguresetObject:@(10)forKey:@"slider.minimumValue"];[row.cellConfigAtConfiguresetObject:@(4)forKey:@"steps"];

Setsteps to@(0) to disable the steps functionality.

Info

Sometimes our apps needs to show data that are not editable. XLForm provides us withXLFormRowDescriptorTypeInfo row type to display not editable info. An example of usage would be showing the app version in the settings part of an app.

Button

Apart from data entry rows, not editable rows and selectors, XLForm has a button rowXLFormRowDescriptorTypeButton that allows us to do any action when selected. It can be configured using a block (clousure), a selector, a segue identifier, segue class or specifing a view controller to be presented. ViewController specification could be done by setting up the view controller class, the view controller storyboard Id or a nib name. Nib name must match view controller class name.

Multivalued Sections (Insert, Delete, Reorder rows)

AnyXLFormSectionDescriptor object can be set up to support row insertion, deletion or reodering. It is possible to enable only one of these modes, a combination or all together.A multivalued section is just a section that support either of these modes.

The most interesting part of multivaluedXLFormSectionDescriptor is that it supports all the types of rows that were shown on theRows section as well as custom rows.

Screenshot of Multivalued Section Example

How to set up a multivalued section

Creating a multivalued section is as simple as use one of the following convenienceXLFormSectionDescriptor initializer:

+(id)formSectionWithTitle:(NSString *)title   sectionOptions:(XLFormSectionOptions)sectionOptions;+(id)formSectionWithTitle:(NSString *)title   sectionOptions:(XLFormSectionOptions)sectionOptionssectionInsertMode:(XLFormSectionInsertMode)sectionInsertMode;

sectionOptions is a bitwise enum parameter that should be used to choose the multivalued section type/s (insert, delete, reorder). Available options areXLFormSectionOptionCanInsert,XLFormSectionOptionCanDelete,XLFormSectionOptionCanReorder.XLFormSectionOptionNone is the value used by default.

sectionInsertMode can be used to select how the insertion mode will look like.XLform has 2 different insertion modes out of the box:XLFormSectionInsertModeLastRow andXLFormSectionInsertModeButton.XLFormSectionInsertModeLastRow is the default value.

Let's see how to create a multivalued section

XLFormDescriptor * form;XLFormSectionDescriptor * section;XLFormRowDescriptor * row;NSArray * nameList = @[@"family",@"male",@"female",@"client"];form = [XLFormDescriptorformDescriptorWithTitle:@"Multivalued examples"];// Enable Insertion, Deletion, Reorderingsection = [XLFormSectionDescriptorformSectionWithTitle:@"MultiValued TextField"sectionOptions:XLFormSectionOptionCanReorder | XLFormSectionOptionCanInsert | XLFormSectionOptionCanDelete];section.multivaluedTag =@"textFieldRow";[formaddFormSection:section];for (NSString * tag in nameList) {// add a row to the section, each row will represent a name of the name list array.row = [XLFormRowDescriptorformRowDescriptorWithTag:nilrowType:XLFormRowDescriptorTypeTexttitle:nil];[[rowcellConfig]setObject:@"Add a new tag"forKey:@"textField.placeholder"];row.value = [tagcopy];[sectionaddFormRow:row];}// add an empty row to the section.row = [XLFormRowDescriptorformRowDescriptorWithTag:nilrowType:XLFormRowDescriptorTypeTexttitle:nil];[[rowcellConfig]setObject:@"Add a new tag"forKey:@"textField.placeholder"];[sectionaddFormRow:row];

Form Values

formValues

You can get all form values invoking-(NSDictionary *)formValues; eitherXLFormViewController instance orXLFormDescriptor instance.

The returnedNSDictionary is created following this rules:

XLForm adds a value for eachXLFormRowDescriptor that belongs to aXLFormSectionDescriptor doesn't have amultivaluedTag value set up. The dictionary key is the value ofXLFormRowDescriptortag property.

For each section that has amultivaluedTag value, XLForm adds a dictionary item with aNSArray as a value, each value of the array is the value of each row contained in the section, and the key is themultivaluedTag.

For instance, if we have a section with themultivaluedTag property equal totags and the following values on the contained rows: 'family', 'male', 'female', 'client', the generated value will betags: ['family', 'male', 'female', 'client']

httpParameters

In same cases the form value we need may differ from the value ofXLFormRowDescriptor instance. This is usually the case of selectors row and when we need to send the form values to some endpoint, the selected value could be a core data object or any other object. In this casesXLForm need to know how to get the value and the description of the selected object.

When using-(NSDictionary *)httpParameters method, XLForm follows the following rules to getXLFormRowDescriptor value:

  1. If the object is aNSString,NSNumber orNSDate, the value is the object itself.
  2. If the object conforms to protocolXLFormOptionObject, XLForm gets the value fromformValue method.
  3. Otherwise it return nil.

multivaluedTag works in the same way as informValues method.

How to create a Custom Row

To create a custom cell you need to create a UITableViewCell extending fromXLFormBaseCell.XLFormBaseCell conforms toXLFormDescriptorCell protocol.

You may be interested in implementXLFormDescriptorCell methods to change the cell behaviour.

@protocolXLFormDescriptorCell <NSObject>@required@property (nonatomic,weak) XLFormRowDescriptor * rowDescriptor;// initialise all objects such as Arrays, UIControls etc...-(void)configure;// update cell when it about to be presented-(void)update;@optional// height of the cell+(CGFloat)formDescriptorCellHeightForRowDescriptor:(XLFormRowDescriptor *)rowDescriptor;// called to check if cell can became first responder-(BOOL)formDescriptorCellCanBecomeFirstResponder;// called to ask cell to assign first responder to relevant UIView.-(BOOL)formDescriptorCellBecomeFirstResponder;// called when cell is selected-(void)formDescriptorCellDidSelectedWithFormController:(XLFormViewController *)controller;// http parameter name used for network request-(NSString *)formDescriptorHttpParameterName;// is invoked when cell becomes firstResponder, could be used for change how the cell looks like when it's the forst responder.-(void)highlight;// is invoked when cell resign firstResponder-(void)unhighlight;@end

Once a custom cell has been created you need to letXLForm know about this cell by adding the row definition tocellClassesForRowDescriptorTypes dictionary.

[[XLFormViewControllercellClassesForRowDescriptorTypes]setObject:[MYCustomCellClassclass]forKey:kMyAppCustomCellType];

or, in case we have used nib file to define theXLBaseDescriptorCell:

[[XLFormViewControllercellClassesForRowDescriptorTypes]setObject:@"nibNameWithoutNibExtension"forKey:kMyAppCustomCellType];

Doing that, XLForm will instantiate the proper cell class when kMyAppCustomCellType row type is used.

Custom Selectors - Selector Row with a custom selector view controller

Almost always the basic selector which allows the user to select one or multiple items from a pushed view controller is enough for our needs, but sometimes we need more flexibility to bring a better user experience to the user or do something not supported by default.

Let's say your app user needs to select a map coordinate or it needs to select a value fetched from a server endpoint. How do we do that easily?

Screenshot of Map Custom Selector

Define the previous selector row is as simple as ...

row = [XLFormRowDescriptorformRowDescriptorWithTag:kSelectorMaprowType:XLFormRowDescriptorTypeSelectorPushtitle:@"Coordinate"];// set up the selector controller classrow.action.viewControllerClass = [MapViewControllerclass];// or//row.action.viewControllerStoryboardId = @"MapViewControllerStoryboardId";// or//row.action.viewControllerNibName = @"MapViewControllerNibName";// Set up a NSValueTransformer to convert CLLocation to NSString, it's used to show the select value description (text).row.valueTransformer = [CLLocationValueTrasformerclass];// Set up the default valuerow.value = [[CLLocationalloc]initWithLatitude:-33longitude:-56];

action.viewControllerClass controller class should conform toXLFormRowDescriptorViewController protocol.

In the example above,MapViewController conforms toXLFormRowDescriptorViewController.

@protocolXLFormRowDescriptorViewController <NSObject>@required@property (nonatomic) XLFormRowDescriptor * rowDescriptor;@end

XLForm sets uprowDescriptor property using theXLFormRowDescriptor instance that belongs to the selector row.

The developer is responsible for update its views with therowDescriptor value as well as set the selected value torowDescriptor from within the custom selector view controller.

Note: the propertiesviewControllerClass,viewControllerNibName orviewControllerStoryboardId are mutually exclusive and are used byXLFormButtonCell andXLFormSelectorCell. If you create a custom cell then you are responsible for using them.

Another example

Screenshot of Dynamic Custom Selector

row = [XLFormRowDescriptorformRowDescriptorWithTag:kSelectorUserrowType:XLFormRowDescriptorTypeSelectorPushtitle:@"User"];row.action.viewControllerClass = [UsersTableViewControllerclass];

You can find the details of these examples within the example repository folder,Examples/Objective-C/Examples/Selectors/CustomSelectors/ andExamples/Objective-C/Examples/Selectors/DynamicSelector.

Dynamic Forms - How to change the form dynamically at runtime

Any change made on theXLFormDescriptor will be reflected on theXLFormViewController tableView. That means that when a section or a row is added or removed XLForm will animate the section or row accordingly.

We shouldn't have to deal withNSIndexPaths or add, removeUITableViewCell anymore.NSIndexPath of a specificTableViewCell changes along the time and this makes very hard to keep track of theNSIndexPath of eachUITableViewCell.

Each XLFormXLFormRowDescriptor row has atag property that is set up in its constructor.XLFormDescriptor has, among other helpers, an specific one to get aXLFormRowDescriptor from atag.It's much easier to manageXLFormRowDescriptors using tags, the tag should be unique and it doesn't change on tableview additions modifications or deletions.

It's important to keep in mind that all theUITableView form modifications have to be made using the descriptors and not making modifications directly on theUITableView.

Usually you may want to change the form when some value change or some row or section is added or removed. For this you can set thedisabled andhidden properties of the rows or sections. For more details seeMake a row or section invisible depending on other rows values.

In order to stay in sync with the form descriptor modifications yourXLFormViewController subclass should override theXLFormDescriptorDelegate methods of 'XLFormViewController'.

Note: It is important to always call the[super ...] method when overriding this delegate's methods.

@protocolXLFormDescriptorDelegate <NSObject>@required-(void)formSectionHasBeenRemoved:(XLFormSectionDescriptor *)formSectionatIndex:(NSUInteger)index;-(void)formSectionHasBeenAdded:(XLFormSectionDescriptor *)formSectionatIndex:(NSUInteger)index;-(void)formRowHasBeenAdded:(XLFormRowDescriptor *)formRowatIndexPath:(NSIndexPath *)indexPath;-(void)formRowHasBeenRemoved:(XLFormRowDescriptor *)formRowatIndexPath:(NSIndexPath *)indexPath;-(void)formRowDescriptorValueHasChanged:(XLFormRowDescriptor *)formRowoldValue:(id)oldValuenewValue:(id)newValue;-(void)formRowDescriptorPredicateHasChanged:(XLFormRowDescriptor *)formRowoldValue:(id)oldValuenewValue:(id)newValuepredicateType:(XLPredicateType)predicateType;@end

For instance if we want to show or hide a row depending on the value of another row:

-(void)formRowDescriptorValueHasChanged:(XLFormRowDescriptor *)rowDescriptor oldValue:(id)oldValue newValue:(id)newValue{// super implmentation MUST be called[superformRowDescriptorValueHasChanged:rowDescriptoroldValue:oldValuenewValue:newValue];if ([rowDescriptor.tagisEqualToString:@"alert"]){if ([[rowDescriptor.valuevalueData]isEqualToNumber:@(0)] ==NO && [[oldValuevalueData]isEqualToNumber:@(0)]){            XLFormRowDescriptor * newRow = [rowDescriptorcopy];            [newRowsetTag:@"secondAlert"];            newRow.title =@"Second Alert";            [self.formaddFormRow:newRowafterRow:rowDescriptor];        }elseif ([[oldValuevalueData]isEqualToNumber:@(0)] ==NO && [[newValuevalueData]isEqualToNumber:@(0)]){            [self.formremoveFormRowWithTag:@"secondAlert"];        }    }

Make a row or section invisible depending on other rows values

Summary

XLForm allows you to define dependencies between rows so that if the value of one row is changed, the behaviour of another one changes automatically. For example, you might have a form where you question the user if he/she has pets. If the answer is 'yes' you might want to ask how their names are.So you can make a row invisible and visible again based on the values of other rows. The same happens with sections.Take a look at the following example:

Screenshot of hiding rows

Of course, you could also do this manually by observing the value of some rows and deleting and adding rows accordingly, but that would be a lot of work which is already done.

How it works

To make the appearance and disappearance of rows and sections automatic, there is a property in each descriptor:

@propertyid hidden;

This id object will normally be a NSPredicate or a NSNumber containing a BOOL. It can be set using any of them or eventually a NSString from which a NSPredicate will be created. In order for this to work the string has to be syntactically correct.

For example, you could set the following string to a row (second) to make it disappear when a previous row (first) contains the value "hide".

second.hidden = [NSStringstringWithFormat:@"$%@ contains[c] 'hide'", first];

This will insert the tag of thefirst after the '$', you can do that manually as well, of course. When the predicate is evaluated every tag variable gets substituted by the corresponding row descriptor.

When the argument is a NSString, a '.value' will be appended to every tag unless the tag is followed by '.isHidden' or '.isDisabled'. This means that a row (or section) might depend on thevalue or thehidden ordisabled properties of another row. When the property is set with a NSPredicate directly, its formatString will not be altered (so you have to append a '.value' after each variable if you want to refer to its value). Setting a NSString is the simplest way but some complex predicates might not work so for those you should directly set a NSPredicate.

You can also set this properties with a bool object which means the value of the property will not change unless manually set.

To get the evaluated boolean value theisHidden method should be called. It will not re-evaluate the predicate each time it gets called but just when the value (or hidden/disabled status) of the rows it depends on changes. When this happens and the return value changes, it will automagically reflect that change on the form so that no other method must be called.

Here is another example, this time a bit more complex:

Screenshot of hiding rows

Disabling rows (set to read-only mode)

Rows can be disabled so that the user can not change them. By default disabled rows have a gray text color. To disable a row the only thing that has to be done is setting its disabled property:

@propertyid disabled;

This property expects a NSNumber containing a BOOL, a NSString or a NSPredicate. A bool will statically disable (or enable the row). The other two work just like the hidden property explained in the section above. This means a row can be disabled and enabled depending on the values of other rows. When a NSString is set, a NSPredicate will be generated taking the string as format string so that it has to be consistent for that purpose.

A difference to the hidden property is that checking the disabled status of a row does not automatically reflect that value on the form. Tharefore, the XLFormViewController's updateFormRow method should be called.

Validations

We can validate the form data using XLForm validation support.

EachXLFormRowDescriptor instance contains a list of validators. We can add validators, remove validators and validate a particular row using these methods:

-(void)addValidator:(id<XLFormValidatorProtocol>)validator;-(void)removeValidator:(id<XLFormValidatorProtocol>)validator;-(XLFormValidationStatus *)doValidation;

We can define our own custom validators just defining a object that conforms toXLFormValidatorProtocol.

@protocolXLFormValidatorProtocol <NSObject>@required-(XLFormValidationStatus *)isValid:(XLFormRowDescriptor *)row;@end

XLFormRegexValidator is an example of a validator we can create.

A very common validation is ensuring that a value is not empty or nil. XLFom exposesrequired XLFormRowDescriptor property to specify required rows.

To get all rows validation errors we can invoke the followingXLFormViewController method:

-(NSArray *)formValidationErrors;

Additional configuration of Rows

XLFormRowDescriptor allow us to configure generic aspects of aUITableViewCell, for example: therowType, thelabel, thevalue (default value), if the cell isrequired,hidden ordisabled, and so on.

You may want to set up another properties of theUITableViewCell. To set up another propertiesXLForm makes use ofKey-Value Coding allowing the developer to set the cell properties by keyPath.

You just have to add the properties tocellConfig orcellConfigAtConfigure dictionary property ofXLFormRowDescriptor.The main difference betweencellConfig andcellConfigAtConfigure is the time when the property is set up.cellConfig properties are set up each time a cell is about to be displayed.cellConfigAtConfigure, on the other hand, set up the property just after the init method of the cell is called and only one time.

Since version 3.3.0 you can also usecellConfigForSelector to configure how the cells of theXLFormOptionsViewController look like when it is shown for a selector row.

For instance if you want to set up the placeholder you can do the following:

row = [XLFormRowDescriptorformRowDescriptorWithTag:@"title"rowType:XLFormRowDescriptorTypeText];[row.cellConfigAtConfiguresetObject:@"Title"forKey:@"textField.placeholder"];[sectionaddFormRow:row];

Let's see how to change the color of the cell label:

Objective C

row = [XLFormRowDescriptorformRowDescriptorWithTag:@"title"rowType:XLFormRowDescriptorTypeText];[row.cellConfigsetObject:[UIColorredColor]forKey:@"textLabel.textColor"];[sectionaddFormRow:row];

Swift

row=XLFormRowDescriptor(tag:"title", rowType: XLFormRowDescriptorTypeText, title:"title")row.cellConfig.setObject(UIColor.blackColor(), forKey:"backgroundColor")row.cellConfig.setObject(UIColor.whiteColor(), forKey:"textLabel.textColor")section.addFormRow(row)

FAQ

How to customize the header and/or footer of a section

For this you should use the UITableViewDelegate methods in your XLFormViewController.This means you should implement one or both of these:

-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section-(UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section

Also you might want to implement the following methods to specify the height for these views:

-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section-(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section

How to assign the first responder on form appearance

Assign the first responder when the form is shown is as simple as setting the propertyassignFirstResponderOnShow toYES. By default the value of the property isNO.

@property (nonatomic)BOOL assignFirstResponderOnShow;

How to set a value to a row.

You should set thevalue property ofXLFormRowDescriptor relevant instance.

@property (nonatomic)id value;

You may notice that thevalue property type isid and you are the responsable to set a value with the proper type. For instance, you should set aNSString value to aXLFormRowDescriptor instance ofXLFormRowDescriptorTypeText.

You may have to update the cell to see the UI changes if the row is already presented.-(void)reloadFormRow:(XLFormRowDescriptor *)formRow method is provided byXLFormViewController to do so.

How to set the default value to a row.

You should do the same asHow to set a value to a row.

How to set up the options to a selector row.

XLForm has several types of selectors rows. Almost all of them need to know which are the values to be selected. For a particularXLFormRowDescriptor instance you specify these values setting aNSArray instance toselectorOptions property.

@propertyNSArray * selectorOptions;

How to get form values

If you want to get the raw form values you should callformValues method ofXLFormDescriptor. Doing that you will get a dictionary containing all the form values.tag property value of each row is used as dictionary key. OnlyXLFormROwDescriptor values for non niltag values are added to the dictionary.

You may be interested in the form values to use it as enpoint parameter. In this casehttpParameters would be useful.

If you need something different, you can iterate over each row...

Objective C

NSMutableDictionary * result = [NSMutableDictionarydictionary];for (XLFormSectionDescriptor * section in self.form.formSections) {if (!section.isMultivaluedSection){for (XLFormRowDescriptor * row in section.formRows) {if (row.tag && ![row.tagisEqualToString:@""]){                 [resultsetObject:(row.value ?: [NSNullnull])forKey:row.tag];             }         }     }else{NSMutableArray * multiValuedValuesArray = [NSMutableArraynew];for (XLFormRowDescriptor * row in section.formRows) {if (row.value){                 [multiValuedValuesArrayaddObject:row.value];             }         }         [resultsetObject:multiValuedValuesArrayforKey:section.multivaluedTag];     } }return result;

Swift

varresults=[String:String]()iflet fullName= form.formRowWithTag(tag.fullName).valueas?String{results[tag.fullName]= fullName}

How to change UITextField length

You can change the length of a UITextField using thecellConfigAtConfigure dictionary property. This value refers to the percentage in relation to the table view cell.

Objective C

[row.cellConfigAtConfiguresetObject:[NSNumbernumberWithFloat:0.7]forKey:XLFormTextFieldLengthPercentage];

Swift

row.cellConfigAtConfigure.setObject(0.7, forKey:XLFormTextFieldLengthPercentage)

**Note:**The same can be achieved for the UITextView when usingXLFormRowDescriptorTypeTextView; just set your percentage for the keyXLFormTextViewLengthPercentage.

How to change a UITableViewCell font

You can change the font or any other table view cell property using thecellConfig dictionary property. XLForm will set upcellConfig dictionary values when the table view cell is about to be displayed.

Objective C

[row.cellConfigsetObject:[UIColorgreenColor]forKey:@"textLabel.textColor"];[row.cellConfigsetObject:[UIFontfontWithName:FONT_LATO_REGULARsize:12.0]forKey:@"textLabel.font"];[row.cellConfigsetObject:[UIFontfontWithName:FONT_LATO_REGULARsize:12.0]forKey:@"detailTextLabel.font"];

Swift

row.cellConfig.setObject(UIColor.whiteColor(), forKey:"self.tintColor")row.cellConfig.setObject(UIFont(name:"AppleSDGothicNeo-Regular", size:17)!, forKey:"textLabel.font")row.cellConfig.setObject(UIColor.whiteColor(), forKey:"textField.textColor")row.cellConfig.setObject(UIFont(name:"AppleSDGothicNeo-Regular", size:17)!, forKey:"textField.font")

For further details, please take a look atUICustomizationFormViewController.m example.

How to set min/max for date cells?

Each XLFormDateCell has aminimumDate and amaximumDate property. To set a datetime row to be a value in the next three days you would do as follows:

Objective C

[row.cellConfigAtConfiguresetObject:[NSDatenew]forKey:@"minimumDate"];[row.cellConfigAtConfiguresetObject:[NSDatedateWithTimeIntervalSinceNow:(60*60*24*3)]forKey:@"maximumDate"];

Swift

row.cellConfig.setObject(NSDate(), forKey:"maximumDate")

How to disable the entire form (read only mode).

disable XLFormDescriptor property can be used to disable the entire form. In order to make the displayed cell to take effect we should reload the visible cells ( [self.tableView reloadData] ).Any other row added after formdisable property is set toYES will reflect the disable mode automatically (no need to reload table view).

How to hide a row or section when another rows value changes.

To hide a row or section you should set its hidden property. The easiest way of doing this is by setting a NSString to it. Let's say you want a section to hide if a previous row, which is a boolean switch, is set to 1 (or YES). Then you would do something like this:

section.hidden = [NSStringstringWithFormat:@"$%@ == 1", previousRow];

That is all!

What do I have to do to migrate from version 2.2.0 to 3.0.0?

The only thing that is not compatible with older versions is that thedisabled property of theXLFormRowDescriptor is anid now. So you just have to add@ before the values you set to it like this:

row.disabled = @YES;// before: row.disabled = YES;

How to change input accessory view (navigation view)

OverridinginputAccessoryViewForRowDescriptor:XLFormViewController method.If you want to disable it completely you can return nil. But you can also customize its whole appearance here.

- (UIView *)inputAccessoryViewForRowDescriptor:(XLFormRowDescriptor *)rowDescriptor{returnnil;//will hide it completely// You can use the rowDescriptor parameter to hide/customize the accessory view for a particular rowDescriptor type.}

How to set up a pushed view controller?

The view controller that will be pushed must conform to theXLFormRowDescriptorViewController protocol which consists of the following property:

@property (nonatomic) XLFormRowDescriptor * rowDescriptor;

This rowDescriptor refers to the selected row of the previous view controller and will be set before the transition to the new controller so that it will be accessible for example in itsviewDidLoad method. That is where that view controller should be set up.

How to change the default appearance of a certain cell

The best way to do this is to extend the class of that cell and override its update and/or configure methods. To make this work you should also update thecellClassesForRowDescriptorTypes dictionary in your subclass of XLFormViewController by setting your custom class instead of the class of the cell you wanted to change.

How to change the returnKeyType of a cell

To change the returnKeyType of a cell you can set thereturnKeyType andnextReturnKeyType properties. The former will be used if there is no navigation enabled or if there is no row after this row. In the other case the latter will be used.If you create a custom cell and want to use these you should conform to theXLFormReturnKeyProtocol protocol.This is how you can set them:

[row.cellConfigAtConfigure setObject:@(UIReturnKeyGo) forKey:@"nextReturnKeyType"];

How to change the height of one cell

If you want to change the height for all cells of one class you should subclass that cell and override the class methodformDescriptorCellHeightForRowDescriptor.If you want to change the height of one individual cell then you can set that height to theheight property of XLFormRowDescripto like this:

XLFormRowDescriptor* row = ...row.height = 55;

How to change the appearance of the cells of a selector view controller (XLFormOptionsViewController)

To change the appearance of the cells of a XLFormOptionsViewController you can use thecellConfigForSelector property on the row descriptor.Example:

[row.cellConfigForSelector setObject:[UIColor redColor] forKey:@"textLabel.textColor"];

How to limit the characters of a XLFormTextFieldCell or a XLFormTextViewCell

You can make this happen using thetextFieldMaxNumberOfCharacters and thetextViewMaxNumberOfCharacters respectively.

[row.cellConfigAtConfigure setObject:@(20) forKey:@"textViewMaxNumberOfCharacters"];

Installation

Swift Package Manager

Starting with Xcode 11, Swift Package Manager is the recommended and preferred way for installing dependencies in Xcode projects. Installing dependencies via SwiftPM does not require the application nor dependencies to be written in Swift.

To add XLForm to your project using SwiftPM follow these steps:

  1. Open your project in Xcode
  2. In the main menu, select File -> Swift Packages -> Add Package Dependency...
  3. In the window, enter the package urlhttps://github.com/xmartlabs/XLForm
  4. Configure the version to be used

To use XLForm in your code, import the module or header files as needed:

#import"XLForm.h"// Obj-c
import XLForm       // Swift

CocoaPods

  1. Add the following line in the project's Podfile file:pod 'XLForm', '~> 4.3'.
  2. Run the commandpod install from the Podfile folder directory.

XLFormhas no dependencies over other pods.

How to use master branch

Often master branch contains most recent features and latest fixes. On the other hand this features was not fully tested and changes on master may occur at any time. For the previous reasons I stongly recommend to fork the repository and manage the updates from master on your own making the proper pull on demand.

To use xmartlabs master branch.....

pod 'XLForm', :git => 'https://github.com/xmartlabs/XLForm.git'

You can replace the repository URL for your forked version url if you wish.

How to use XLForm in Swift files

If you have installed XLForm with cocoapods and have setuse_frameworks! in your Podfile, you can addimport XLForm to any Swift file.

If you are using cocoapods but have not setuse_frameworks! in your Podfile, add#import <XLForm/XLForm.h> to your bridging header file.

For further details on how to create and configure the bridging header file visitImporting Objective-C into Swift.

Carthage

In yourCartfile add:

github "xmartlabs/XLForm" ~> 4.2

Using git submodules

  • Clone XLForm as a gitsubmodule by running the following command from your project root git folder.
$ git submodule add https://github.com/xmartlabs/XLForm.git
  • Open XLForm folder that was created by the previous git submodule command and drag the XLForm.xcodeproj into the Project Navigator of your application's Xcode project.

  • Select the XLForm.xcodeproj in the Project Navigator and verify the deployment target matches with your application deployment target.

  • Select your project in the Xcode Navigation and then select your application target from the sidebar. Next select the "General" tab and click on the + button under the "Embedded Binaries" section.

  • SelectXLForm.framework and we are done!

Requirements

  • ARC
  • iOS 9.0 and above
  • Xcode 9.0+ (11.0+ for installation via Swift Package Manager)

Release Notes

Have a look at theCHANGELOG

Author

Martin Barreto (@mtnBarreto)

Contact

Any suggestion or question? Please create a Github issue or reach us out.

xmartlabs.com (@xmartlabs)

About

XLForm is the most flexible and powerful iOS library to create dynamic table-view forms. Fully compatible with Swift & Obj-C.

Topics

Resources

License

Stars

Watchers

Forks

Sponsor this project

 

Packages

No packages published

Languages


[8]ページ先頭

©2009-2025 Movatter.jp