Tab bar refactor

* Fixes issue #167
* Added PM::TabBarController
* Moved some PM::Tab methods into PM::TabBarController
* Moved some tab-related accessors into PM::Tab
* Allowed `open_tab` from AppDelegate and on the PM::TabBarController
directly
* Added tests
* Added a method: set_tab_bar_badge(number)
* Also fixed an error in the cell identifier creation code that was
creating too many identifiers

75 specifications (144 requirements), 0 failures, 0 errors
This commit is contained in:
Jamon Holmgren
2013-06-28 11:58:05 -07:00
parent be5c9bb0a3
commit cb88e225fe
7 changed files with 102 additions and 71 deletions

View File

@@ -41,6 +41,10 @@ namespace :spec do
App.config.instance_variable_set("@spec_files", spec_files)
Rake::Task["simulator"].invoke
end
task :func do
Rake::Task["spec:functional"].invoke
end
task :functional do
App.config.spec_mode = true

View File

@@ -0,0 +1,44 @@
module ProMotion
class TabBarController < UITabBarController
def self.new(*screens)
tab_bar_controller = alloc.init
view_controllers = []
screens = screens.flatten.map { |s| s.respond_to?(:new) ? s.new : s } # Initialize any classes
tag_index = 0
screens.each do |s|
s.tabBarItem.tag = tag_index
s.tab_bar = tab_bar_controller if s.respond_to?("tab_bar=")
view_controllers << (s.navigationController || s)
tag_index += 1
s.on_load if s.respond_to?(:on_load)
end
tab_bar_controller.viewControllers = view_controllers
tab_bar_controller
end
def open_tab(tab)
if tab.is_a? String
selected_tab_vc = find_tab(tab)
elsif tab.is_a? Numeric
selected_tab_vc = viewControllers[tab]
end
if selected_tab_vc
self.selectedViewController = selected_tab_vc if selected_tab_vc
else
PM.logger.error "Unable to open tab #{tab.to_s} -- not found."
nil
end
end
def find_tab(tab_title)
self.viewControllers.select{ |vc| vc.tabBarItem.title == tab_title }.first
end
end
end

View File

@@ -1,50 +1,32 @@
module ProMotion
module Tabs
def tab_bar_controller(*screens)
tab_bar_controller = UITabBarController.alloc.init
view_controllers = []
tag_index = 0
screens.map! { |s| s.respond_to?(:new) ? s.new : s } # Initialize any classes
screens.each do |s|
s = s.new if s.respond_to?(:new)
s.tabBarItem.tag = tag_index
s.parent_screen = self if self.is_a?(UIViewController) && s.respond_to?("parent_screen=")
s.tab_bar = tab_bar_controller if s.respond_to?("tab_bar=")
view_controllers << (s.navigationController || s)
tag_index += 1
s.on_load if s.respond_to?(:on_load)
end
tab_bar_controller.viewControllers = view_controllers
tab_bar_controller
end
attr_accessor :tab_bar, :tab_bar_item
def open_tab_bar(*screens)
tab_bar = tab_bar_controller(*screens)
self.tab_bar = PM::TabBarController.new(screens)
a = self.respond_to?(:open_root_screen) ? self : UIApplication.sharedApplication.delegate
delegate = self.respond_to?(:open_root_screen) ? self : UIApplication.sharedApplication.delegate
a.open_root_screen(tab_bar)
tab_bar
delegate.open_root_screen(self.tab_bar)
self.tab_bar
end
def open_tab(tab)
if tab.is_a? String
return self.select(self.tab_bar, title: tab)
elsif tab.is_a? Numeric
self.tab_bar.selectedIndex = tab
return self.tab_bar.viewControllers[tab]
else
$stderr.puts "Unable to open tab #{tab.to_s} because it isn't a string or number."
end
self.tab_bar.open_tab(tab)
end
def set_tab_bar_item(args = {})
self.tab_bar_item = args
refresh_tab_bar_item
end
def refresh_tab_bar_item
self.tabBarItem = create_tab_bar_item(self.tab_bar_item) if self.tab_bar_item && self.respond_to?(:tabBarItem=)
end
def set_tab_bar_badge(number)
self.tab_bar_item[:badge] = number
refresh_tab_bar_item
end
def create_tab_bar_icon(icon, tag)
@@ -69,19 +51,7 @@ module ProMotion
return tab_bar_item
end
def select(tab_bar_controller, title: title)
root_controller = nil
tab_bar_controller.viewControllers.each do |vc|
if vc.tabBarItem.title == title
tab_bar_controller.selectedViewController = vc
root_controller = vc
break
end
end
root_controller
end
def replace_current_item(tab_bar_controller, view_controller: vc)
controllers = NSMutableArray.arrayWithArray(tab_bar_controller.viewControllers)
controllers.replaceObjectAtIndex(tab_bar_controller.selectedIndex, withObject: vc)

View File

@@ -5,7 +5,7 @@ module ProMotion
include ProMotion::Tabs
include ProMotion::SplitScreen if NSBundle.mainBundle.infoDictionary["UIDeviceFamily"].include?("2")
attr_accessor :parent_screen, :first_screen, :tab_bar_item, :tab_bar, :modal, :split_screen
attr_accessor :parent_screen, :first_screen, :tab_bar_item, :modal, :split_screen
def on_create(args = {})
unless self.is_a?(UIViewController)
@@ -14,9 +14,7 @@ module ProMotion
self.title = self.class.send(:get_title)
args.each do |k, v|
self.send("#{k}=", v) if self.respond_to?("#{k}=")
end
args.each { |k, v| self.send("#{k}=", v) if self.respond_to?("#{k}=") }
self.add_nav_bar(args) if args[:nav_bar]
self.navigationController.toolbarHidden = !args[:toolbar] unless args[:toolbar].nil?
@@ -45,15 +43,6 @@ module ProMotion
val
end
def set_tab_bar_item(args = {})
self.tab_bar_item = args
refresh_tab_bar_item
end
def refresh_tab_bar_item
self.tabBarItem = create_tab_bar_item(self.tab_bar_item) if self.tab_bar_item
end
def add_nav_bar(args = {})
self.navigation_controller ||= begin
self.first_screen = true if self.respond_to?(:first_screen=)

View File

@@ -71,8 +71,8 @@ module ProMotion
def set_data_cell_defaults(data_cell)
data_cell[:cell_style] ||= UITableViewCellStyleDefault
data_cell[:cell_identifier] ||= build_cell_identifier(data_cell)
data_cell[:cell_class] ||= PM::TableViewCell
data_cell[:cell_identifier] ||= build_cell_identifier(data_cell)
data_cell[:accessory] = {
view: data_cell[:accessory],
@@ -85,9 +85,9 @@ module ProMotion
end
def build_cell_identifier(data_cell)
ident = "#{data_cell[:cell_class]}"
ident = "#{data_cell[:cell_class].to_s}"
ident << "-#{data_cell[:stylename].to_s}" if data_cell[:stylename] # For Teacup
ident << "-#{data_cell[:accessory][:view].to_s}" if data_cell[:accessory]
ident << "-accessory" if data_cell[:accessory]
ident << "-subtitle" if data_cell[:subtitle]
ident << "-remoteimage" if data_cell[:remote_image]
ident << "-image" if data_cell[:image]

View File

@@ -50,5 +50,29 @@ describe "PM::Tabs" do
@screen4.open_tab 0
@tab_bar.selectedIndex.should == 0
end
it "should allow opening a tab from the app_delegate" do
@app.open_tab "Screen 2"
@tab_bar.selectedIndex.should == 1
@app.open_tab "Screen 3"
@tab_bar.selectedIndex.should == 2
@app.open_tab "Screen 4"
@tab_bar.selectedIndex.should == 3
@app.open_tab "Screen 1"
@tab_bar.selectedIndex.should == 0
end
it "should allow opening a tab by accessing the tab bar directly" do
@tab_bar.open_tab "Screen 2"
@tab_bar.selectedIndex.should == 1
@tab_bar.open_tab "Screen 3"
@tab_bar.selectedIndex.should == 2
@tab_bar.open_tab "Screen 4"
@tab_bar.selectedIndex.should == 3
@tab_bar.open_tab "Screen 1"
@tab_bar.selectedIndex.should == 0
end
end

View File

@@ -8,7 +8,7 @@ describe "PM::TableViewCellModule" do
action: :tapped_cell_1,
height: 50, # manually changes the cell's height
cell_style: UITableViewCellStyleSubtitle,
cell_identifier: "Cell",
cell_identifier: "Custom Cell",
cell_class: PM::TableViewCell,
layer: { masks_to_bounds: true },
background_color: UIColor.redColor,
@@ -54,12 +54,12 @@ describe "PM::TableViewCellModule" do
end
it "should have the right custom re-use identifier" do
@subject.reuseIdentifier.should == "Cell"
@subject.reuseIdentifier.should == "Custom Cell"
end
it "should have the right generated re-use identifier" do
ip = NSIndexPath.indexPathForRow(2, inSection: 1)
subject = @screen.tableView(@screen.table_view, cellForRowAtIndexPath: ip)
subject.reuseIdentifier.should == "Cell-accessory"
subject.reuseIdentifier.should == "ProMotion::TableViewCell-accessory"
end
it "should have the correct height" do