ProMotion introduces a new object called "Screens". Screens have a one-to-one relationship with your app's screens and can (usually) take the place of view controllers.
Typical app file structure:
app/
screens/
photos/
list_photos_screen.rb
show_photo_screen.rb
edit_photo_screen.rb
home_screen.rb
settings_screen.rb
models/
view_controllers/
views/
app_delegate.rb
Loading your home screen:
# In /app/app_delegate.rb (note that AppDelegate extends ProMotion::AppDelegateParent)
class AppDelegate < ProMotion::AppDelegateParent
def on_load(options)
open_screen MyHomeScreen.new(nav_bar: true)
end
end
Creating a basic screen:
class HomeScreen < ProMotion::Screen
title "Home"
def on_load
# Set up the elements in your view with add_element:
@label = add_element UILabel.alloc.initWithFrame(CGRectMake(5, 5, 20, 20)), {
text: "This is awesome!",
font: UIFont.systemFontOfSize(18)
}
end
def on_appear
# Refresh the data if you want
end
end
Creating a tabbed bar:
def on_load(options)
@home = MyHomeScreen.new(nav_bar: true)
@settings = SettingsScreen.new
@contact = ContactScreen.new(nav_bar: true)
open_tab_bar @home, @settings, @contact
end
Any view item (UIView, UIButton, etc) can be used with add_element. The second argument is a hash of settings that get applied to the element before it is dropped into the view.
@label = add_element UILabel.alloc.initWithFrame(CGRectMake(5, 5, 20, 20)), {
text: "This is awesome!",
font: UIFont.UIFont.systemFontOfSize(18)
}
Add a nav_bar button and a tab_bar icon:
set_nav_bar_right_button "Save", action: :save_something, type: UIBarButtonItemStyleDone
set_tab_bar_item title: "Contacts", system_icon: UITabBarSystemItemContacts
Open a new screen:
def settings_button_tapped
# ...with a class...
open_screen SettingsScreen
# ...or with an instance...
@settings_screen = SettingsScreen.new
open_screen @settings_screen
end
Open a new screen as a modal:
open_screen SettingsScreen, modal: true
You can pass in arguments to other screens if they have accessors:
class HomeScreen < ProMotion::Screen
# ...
def settings_button_tapped
open_screen ProfileScreen.new(user: some_user)
end
end
class ProfileScreen < ProMotion::Screen
attr_accessor :user
def on_load
self.user # => some_user instance
end
end
Close a screen (modal or in a nav controller), passing back arguments to the previous screen's "on_return" method:
class ItemScreen
# ...
def save_and_close
if @model.save
close_screen(model_saved: true)
end
end
end
class MainScreen < ProMotion::Screen
# ...
def on_return(args = {})
if args[:model_saved]
self.reload_something
end
end
end
Use a custom view controller:
def on_load
set_view_controller MyCustomViewController
# Note: on_appear will not fire when using a custom
# view controller.
end
The helper add_element takes any view object and adds it to the current view. You can also use the helper ProMotion::ViewHelper.set_attributes(view, attributes) to do the same thing without adding it to the current view. Screens include this helper by default.
@element = add_element UIView.alloc.initWithFrame(CGRectMake(0, 0, 20, 20)), {
backgroundColor: UIColor.whiteColor
}
@element = set_attributes UIView.alloc.initWithFrame(CGRectMake(0, 0, 20, 20)), {
backgroundColor: UIColor.whiteColor
}
You can create sectioned table screens easily. TableScreen, SectionedTableScreen, GroupedTableScreen. This is loosely based on motion-table (there are a few minor differences).
class SettingsScreen < ProMotion::GroupedTableScreen
title "Settings"
def on_load
add_right_nav_button(label: "Save", action: :save)
set_tab_bar_item(title: "Settings", icon: "settings.png")
end
# table_data is automatically called. Use this format in the return value.
# Grouped tables are the same as plain tables
def table_data
[{
title: "Your Account",
cells: [
{ title: "Edit Profile", action: :edit_profile, arguments: { id: 3 } },
{ title: "Log Out", action: :log_out },
{ title: "Notification Settings", action: :notification_settings }
]
}, {
title: "App Stuff",
cells: [
{ title: "About", action: :show_about },
{ title: "Feedback", action: :show_feedback }
]
}]
end
# This method allows you to create a "jumplist", the index on the right side of the table
def table_data_index
return ["A", "B", "C"]
end
# Your table cells, when tapped, will execute the corresponding actions and pass in arguments:
def edit_profile(arguments)
# ...
end
end
(not comprehensive yet...working on this)
Class or Module | Method | Description |
---|---|---|
Screen | is_modal? | Returns if the screen was opened in a modal window. |
has_nav_bar? | Returns if the screen is contained in a navigation controller. | |
set_tab_bar_item(args) |
Creates the tab that is shown in a tab bar item. Arguments: { icon: "imagename", systemIcon: UISystemIconContacts, title: "tabtitle" }
|
I'm a big believer in MVC (I'm a Rails developer, too). I found that most of the time working in RubyMotion seems to happen in the ViewControllers and views are mainly custom elements. This pattern is probably best for navigation controller and tab bar based apps.
Feedback welcome via twitter @jamonholmgren or email jamon@clearsightstudio.com.
I'm really looking for feedback. Tweet me with your ideas or open a ticket (I don't mind!) and let's discuss.