ProMotion-XLForm provides a PM::XLFormScreen for ProMotion powered by the CocoaPod XLForm.
gem 'ProMotion-XLForm'Then:
$ bundle
$ rake pod:installPM::XLFormScreen includes PM::ScreenModule so you'll have all the same ProMotion screen methods available.
To create a form screen, subclass PM::XLFormScreen and define a form_data method.
class TestFormScreen < PM::XLFormScreen
def form_data
genders = [
{ id: :male, name: 'Male' },
{ id: :female, name: 'Female' },
{ id: :other, name: 'Other' },
]
[
{
title: 'Account information',
cells: [
{
title: 'Email',
name: :email,
type: :email,
placeholder: 'Enter your email',
required: true
},
{
title: 'Name',
name: :name,
type: :text,
value: 'Default value'
},
{
title: 'Gender',
name: :gender,
type: :selector_push,
options: Hash[genders.map do |gender|
[gender[:id], gender[:name]]
end]
}
]
}
]
end
end- :text
- :name
- :url
- :password
- :number
- :phone
- :account
- :integer
- :decimal
- :textview
- :zip_code
- :selector_push
- :selector_popover
- :selector_action_sheet
- :selector_alert_view
- :selector_picker_view
- :selector_picker_view_inline
- :multiple_selector
- :multiple_selector_popover
- :selector_left_right
- :selector_segmented_control
- :date_inline
- :datetime_inline
- :time_inline
- :countdown_timer_inline
- :date
- :datetime
- :time
- :countdown_timer
- :datepicker
- :picker
- :slider
- :check
- :switch
- :button
- :info
- :step_counter
- :image (ProMotion-XLForm specific)
- :color (ProMotion-XLForm specific using RSColorPicker)
The form_options class method allows you to customize the default behavior of the form.
class TestFormScreen < PM::XLFormScreen
form_options on_save: :save_form, # adds a "Save" button in the nav bar and calls this method
on_cancel: :cancel_form, # adds a "Cancel" button in the nav bar and calls this method
required: :asterisks, # display an asterisk next to required fields
auto_focus: true # the form will focus on the first focusable field
def save_form(values)
dismiss_keyboard
mp values
end
def cancel_form
end
endBy default, no buttons are displayed in the nav bar unless you configure the on_save or on_cancel options.
You can either pass the name of the method that you want to call when that button is tapped, or you can pass a hash of options, allowing you to configure the title of the button.
Hash Options:
titleorsystem_item- The button text or system item that will be displayed.action- The method that will be called when the button is tapped.
form_options on_cancel: { system_item: :trash, action: :cancel_form },
on_save: { title: 'Continue', action: :continue }system_item can be any UIBarButtonSystemItem constant or one of the following symbols:
:done, :cancel, :edit, :save, :add, :flexible_space, :fixed_space, :compose,
:reply, :action, :organize, :bookmarks, :search, :refresh, :stop, :camera,
:trash, :play, :pause, :rewind, :fast_forward, :undo, :redoIf you would like to display a button as part of your form, you could do something like this:
form_options on_save: :my_save_method
def form_data
[
{
title: 'Save',
name: :save,
type: :button,
on_click: -> (cell) {
on_save(nil)
}
}
]
end
def my_save_method(values)
mp values
endYou can get the values of your form with values. You can call dismiss_keyboard before before calling values to ensure you capture the input from the currently focused form element.
You can also get validation errors with validation_errors and check if the form is valid with valid?.
You can also get a specific value with value_for_cell(:my_cell).
on_change, on_add and on_remove are available for cells, on_add and on_remove are available for sections.
{
title: 'Sex',
name: :sex,
type: :selector_push,
options: {
male: 'Male',
female: 'Female',
other: 'Other'
},
# An optional row paramater may be passed |old_value, new_value|
on_change: lambda do |old_value, new_value|
puts "Changed from #{old_value} to #{new_value}"
end
}
# An optional row paramater may be passed to on_change:
# on_change: lambda do |old_value, new_value, row|
# puts "Changed from #{old_value} to #{new_value}"
# row.setTitle(new_value)
# self.reloadFormRow(row) if old_value != new_value
# end{
title: 'Multiple value',
name: :multi_values,
options: [:insert, :delete, :reorder],
cells: [
{
title: 'Add a new tag',
name: :tag,
type: :text
}
]
}You can create a custom subform with a few options
{
title: 'Custom section',
cells: [
{
title: 'Custom',
name: :custom,
cells: [
{
title: 'Some text',
name: :some_text,
type: :text
},
{
title: 'Other text',
name: :some_other_text,
type: :text
}
]
}
]
}By default, the cell will print a Hash.inspect of your subcells. You can change this by creating a valueTransformer and set value_transformer:.
{
title: 'Custom',
name: :custom,
value_transformer: MyValueTransformer
cells: []
}
class MyValueTransformer < PM::ValueTransformer
def transformedValue(value)
return nil if value.nil?
str = []
str << value['some_text'] if value['some_text']
str << value['some_other_text'] if value['some_other_text']
str.join(',')
end
endFor a more advanced custom selector, you can set view_controller_class:.
{
title: 'Person',
name: 'person',
type: :selector_push,
view_controller_class: PeopleListScreen
}Here is an example of a table screen. Note that the rowDescriptor setter must be implemented. In order to pass the value back to the previous form screen, update the value of the rowDescriptor. Note that XLForm will set the rowDescriptor later in your view controller's initialization process than you might expect.
class PeopleListScreen < PM::TableScreen
attr_accessor :rowDescriptor
def table_data
[{
title: @rowDescriptor.title,
cells: People.all.map do |person|
{
title: person.name,
action: -> {
rowDescriptor.value = person.id
close # go back to the previous screen
}
}
end
}]
end
endSee XLForm documentation for more information.
You can use your own cell by providing cell_class
{
title: 'MyCustomCell',
name: :custom_cell,
cell_class: MyCustomCell
}
class MyCustomCell < PM::XLFormCell
def initWithStyle(style, reuseIdentifier: reuse_identifier)
super.tap do
@label = UILabel.new
self.contentView.addSubview(@label)
end
end
def update
super
@label.text = value
@label.sizeToFit
end
endIn your cell, you can set the value with self.value= and get the value with self.value
You can add validators to cells.
{
title: 'Email',
name: :email,
type: :email,
required: true,
validators: {
email: true
}
}:email and :url are available out of the box, as well as :regex. You will have to provide a valid regex and a message.
{
title: 'Only letters',
name: :letters,
type: :text,
required: true,
validators: {
regex: { regex: /^[a-zA-Z]+$/, message: "Only letters please !" }
}
}Finally, you can provide a PM::Validator with a valid?(cell) method.
You can show/hide cells depending on a cell value with a predicate
{
title: 'Hide and seek',
cells: [
{
title: 'Switch me',
type: :switch,
name: :hide_and_seek,
value: true
},
{
title: 'Appear when switch is on',
name: :show_me,
type: :info,
hidden: {
# the cell name wich will "trigger" the visibility
name: :hide_and_seek,
# the operand. Valid operands are :equal, :not_equal, :contains, :not_contains
is: :equal,
# the value which trigger the visibility
value: true }
},
{
title: 'Appear when switch is off',
name: :hide_me,
type: :info,
# you can also write it this way
hidden: ':hide_and_seek == false'
# also valid ':some_text contains "a text"'
# ':some_text not contains "a text"'
}
]
}You can add :on_click on :button which accepts 0 or 1 argument (the cell).
{
title: 'Click me',
name: :click_me,
type: :button,
on_click: -> (cell) {
mp "You clicked me"
}
}You can change the appearance of the cell using the appearance hash
{
title: 'Options',
name: 'options',
type: :selector_push,
appearance: {
font: UIFont.fontWithName('Helvetica Neue', size: 15.0),
detail_font: UIFont.fontWithName('Helvetica Neue', size: 12.0),
color: UIColor.greenColor,
detail_color: UIColor.blueColor,
background_color: UIColor.grayColor
},
options: {
"value_1" => "Value 1",
"value_2" => "Value 2",
"value_3" => "Value 3",
"value_4" => "Value 4",
}
},
{
title: 'Alignment',
name: :align,
type: :text,
appearance: {
alignment: :right # or NSTextAlignmentRight
}
}You can also pass any key-value to configure your cell. Take a look at this for more information
{
appearance: {
"slider.tintColor" => UIColor.grayColor
}
}For the text based cells (like :text, :password, :number, :integer, :decimal), you can specify a keyboard_type. The following keyboard types are available :
- :default
- :ascii
- :numbers_punctuation
- :url
- :number_pad
- :phone_pad
- :name_phone_pad
- :decimal_pad
- :web_search
- :alphabet
If you use RMQ or RedPotion, you can style the screen with
def form_view(st)
end- Fork it
- Create your feature branch (
git checkout -b my-new-feature) - Commit your changes (
git commit -am 'Add some feature') - Make some specs pass
- Push to the branch (
git push origin my-new-feature) - Create new Pull Request
Released under the MIT license.