Permalink
Browse files

refactor view builder into smaller classes

  • Loading branch information...
Sean Ho
Sean Ho committed May 15, 2012
1 parent 30f47b6 commit 155c1475ff28c1332467282d5154d29492cb848a
View
@@ -17,7 +17,7 @@ Or refer to the blog post [Using 3rd Party Ruby Library in RubyMotion](http://re
def viewDidLoad
UI::Layout.setup(view) do
label width: 200, height: 20, text: "Choose your lucky word", color: UIColor.darkGrayColor
- image_view top: 50, left: 50, right: 50, image:UIImage.imageName("sample.jpg")
+ image_view top: 50, left: 50, right: 50, image: "sample.jpg"
end
end
````
@@ -37,6 +37,7 @@ end
````
### UIKit support
+- UIActivityIndicatorView via `activity_indicator`
- UIButton via `button`
- UIDatePicker via `date_picker`
- UIImageView via `image_view`
@@ -61,20 +62,16 @@ end
### Custom view support
````ruby
-def viewDidLoad
- UI::Layout.setup(view) do
- add CustomViewClass, name: "custom_view"...
- end
+UI::Layout.setup(view) do
+ add CustomViewClass, name: "custom_view"...
end
````
### View anchoring
````ruby
-def viewDidLoad
- UI::Layout.setup(view) do
- toolbar bottom: 10, left: 10, right: 10, anchors: [:left, :right, :bottom]
- end
+UI::Layout.setup(view) do
+ toolbar bottom: 10, left: 10, right: 10, anchors: [:left, :right, :bottom]
end
````
View
@@ -5,4 +5,12 @@ Motion::Project::App.setup do |app|
# Use `rake config' to see complete project settings.
app.name = 'SimpleView'
app.files += Dir.glob(File.join(app.project_dir, 'lib/**/*.rb'))
+ app.files_dependencies 'lib/builders/ui_control_builder.rb' => 'lib/builders/ui_view_builder.rb'
+ app.files_dependencies 'lib/builders/ui_activity_indicator_view_builder.rb' => 'lib/builders/ui_view_builder.rb'
+ app.files_dependencies 'lib/builders/ui_button_builder.rb' => 'lib/builders/ui_control_builder.rb'
+ app.files_dependencies 'lib/builders/ui_image_view_builder.rb' => 'lib/builders/ui_view_builder.rb'
+ app.files_dependencies 'lib/builders/ui_progress_view_builder.rb' => 'lib/builders/ui_view_builder.rb'
+ app.files_dependencies 'lib/builders/ui_segmented_control_builder.rb' => 'lib/builders/ui_control_builder.rb'
+ app.files_dependencies 'lib/builders/ui_table_view_builder.rb' => 'lib/builders/ui_view_builder.rb'
+ app.files_dependencies 'lib/builders/ui_table_view_cell_builder.rb' => 'lib/builders/ui_view_builder.rb'
end
@@ -0,0 +1,8 @@
+module UI
+ class UIActivityIndicatorViewBuilder < UIViewBuilder
+ def view_for_class(klass, options = {})
+ style = options.delete(:style) || UIActivityIndicatorViewStyleWhite
+ klass.alloc.initWithActivityIndicatorStyle(style)
+ end
+ end
+end
@@ -0,0 +1,8 @@
+module UI
+ class UIButtonBuilder < UIControlBuilder
+ def view_for_class(klass, options = {})
+ button_type = options.delete(:buttonType) || options.delete(:button_type) || UIButtonTypeRoundedRect
+ klass.buttonWithType(button_type)
+ end
+ end
+end
@@ -0,0 +1,7 @@
+module UI
+ class UIControlBuilder < UIViewBuilder
+ def view_for_class(klass, options = {})
+ klass.alloc.init
+ end
+ end
+end
@@ -0,0 +1,29 @@
+module UI
+ class UIImageViewBuilder < UIViewBuilder
+ def view_for_class(klass, options = {})
+ image = extract_image(options, :image)
+ highlighted_image = extract_image(options, [:highlightedImage, :highlighted_image])
+
+ if image && highlighted_image
+ klass.alloc.initWithImage(image, highlightedImage:highlighted_image)
+ elsif image
+ klass.alloc.initWithImage(image)
+ else
+ klass.alloc.initWithFrame(CGRectZero)
+ end
+ end
+
+ def extract_image(options, key)
+ if key.is_a?(Array)
+ key.each do |k|
+ image = options.delete(k)
+ break unless image.nil?
+ end
+ else
+ image = options.delete(key)
+ end
+ image = UIImage.imageNamed(image) if !image.nil? && image.is_a?(String)
+ image
+ end
+ end
+end
@@ -0,0 +1,8 @@
+module UI
+ class UIProgressViewBuilder < UIViewBuilder
+ def view_for_class(klass, options = {})
+ style = options.delete(:style) || UIProgressViewStyleDefault
+ klass.alloc.initWithProgressViewStyle(style)
+ end
+ end
+end
@@ -0,0 +1,8 @@
+module UI
+ class UISegmentedControlBuilder < UIControlBuilder
+ def view_for_class(klass, options = {})
+ items = options.delete(:items) || []
+ klass.alloc.initWithItems(items)
+ end
+ end
+end
@@ -0,0 +1,8 @@
+module UI
+ class UITableViewBuilder < UIViewBuilder
+ def view_for_class(klass, options = {})
+ style = options.delete(:style) || UITableViewStylePlain
+ klass.alloc.initWithFrame(CGRectZero, style: style)
+ end
+ end
+end
@@ -0,0 +1,9 @@
+module UI
+ class UITableViewCellBuilder < UIViewBuilder
+ def view_for_class(klass, options = {})
+ style = options.delete(:style) || UITableViewCellStyleDefault
+ identifier = options.delete(:reuseIdentifier) || options.delete(:reuse_identifier)
+ klass.alloc.initWithStyle(style, reuseIdentifier: identifier)
+ end
+ end
+end
@@ -0,0 +1,35 @@
+module UI
+ class UIViewBuilder
+ STRUCTS_MAP = {
+ CGAffineTransform => Proc.new {|v| NSValue.valueWithCGAffineTransform(v) },
+ CGPoint => Proc.new {|v| NSValue.valueWithCGPoint(v) },
+ CGRect => Proc.new {|v| NSValue.valueWithCGRect(v) },
+ CGSize => Proc.new {|v| NSValue.valueWithCGSize(v) },
+ UIEdgeInsets => Proc.new {|v| NSValue.valueWithUIEdgeInsets(v) },
+ UIOffset => Proc.new {|v| NSValue.valueWithUIOffset(v) }
+ }
+
+ attr_reader :view
+
+ def build(klass, options = {})
+ @view = view_for_class(klass, options)
+
+ unless options.nil?
+ options.each do |k,v|
+ options[k] = STRUCTS_MAP[v.class].call(v) if STRUCTS_MAP.has_key?(v.class)
+ end
+ self.setValuesForKeysWithDictionary(options)
+ end
+
+ @view
+ end
+
+ def view_for_class(klass, options = {})
+ klass.alloc.initWithFrame(CGRectZero)
+ end
+
+ def setValue(value, forUndefinedKey:key)
+ @view.setValue(value, forKey: key)
+ end
+ end
+end
View
@@ -0,0 +1,16 @@
+class UIColor
+ # reference: http://color.rubyforge.org/
+ def self.from_html(html_colour)
+ html_colour = html_colour.gsub(%r{[#;]}, '')
+ case html_colour.size
+ when 3
+ colours = html_colour.scan(%r{[0-9A-Fa-f]}).map { |el| (el * 2).to_i(16) }
+ when 6
+ colours = html_colour.scan(%r<[0-9A-Fa-f]{2}>).map { |el| el.to_i(16) }
+ else
+ raise ArgumentError
+ end
+
+ UIColor.colorWithRed(colours[0]/255.0, green: colours[1]/255.0, blue: colours[2]/255.0, alpha: 1)
+ end
+end
View
@@ -1,14 +1,5 @@
module UI
class Layout
- STRUCTS_MAP = {
- CGAffineTransform => Proc.new {|v| NSValue.valueWithCGAffineTransform(v) },
- CGPoint => Proc.new {|v| NSValue.valueWithCGPoint(v) },
- CGRect => Proc.new {|v| NSValue.valueWithCGRect(v) },
- CGSize => Proc.new {|v| NSValue.valueWithCGSize(v) },
- UIEdgeInsets => Proc.new {|v| NSValue.valueWithUIEdgeInsets(v) },
- UIOffset => Proc.new {|v| NSValue.valueWithUIOffset(v) }
- }
-
attr_accessor :view, :locals
def self.setup(view = nil, locals = {}, &block)
@@ -28,13 +19,6 @@ def initialize(view = nil, locals = {})
def add(klass, options = {}, &block)
subview = ViewBuilder.build(klass, options)
- unless options.nil?
- options.each do |k,v|
- options[k] = STRUCTS_MAP[v.class].call(v) if STRUCTS_MAP.has_key?(v.class)
- end
- subview.setValuesForKeysWithDictionary(options)
- end
-
if block_given?
child_layout = Layout.new(subview, @locals)
child_layout.instance_eval &block
@@ -70,15 +54,15 @@ def web_view(options = {}, &block) add(UIWebView, options, &block); e
class ViewBuilder
@@builders = {
- UIView => Proc.new {|klass, options| ViewBuilder.create_ui_view(klass, options) },
- UIControl => Proc.new {|klass, options| ViewBuilder.create_ui_control(klass, options) },
- UIActivityIndicatorView => Proc.new {|klass, options| ViewBuilder.create_ui_activity_indicator_view(klass, options) },
- UIButton => Proc.new {|klass, options| ViewBuilder.create_ui_button(klass, options) },
- UIImageView => Proc.new {|klass, options| ViewBuilder.create_ui_image_view(klass, options) },
- UIProgressView => Proc.new {|klass, options| ViewBuilder.create_ui_progress_view(klass, options) },
- UISegmentedControl => Proc.new {|klass, options| ViewBuilder.create_ui_segmented_control(klass, options) },
- UITableView => Proc.new {|klass, options| ViewBuilder.create_ui_table_view(klass, options) },
- UITableViewCell => Proc.new {|klass, options| ViewBuilder.create_ui_table_view_cell(klass, options) }
+ UIView => UIViewBuilder.new,
+ UIControl => UIControlBuilder.new,
+ UIActivityIndicatorView => UIActivityIndicatorViewBuilder.new,
+ UIButton => UIButtonBuilder.new,
+ UIImageView => UIImageViewBuilder.new,
+ UIProgressView => UIProgressViewBuilder.new,
+ UISegmentedControl => UISegmentedControlBuilder.new,
+ UITableView => UITableViewBuilder.new,
+ UITableViewCell => UITableViewCellBuilder.new
}
def self.build(klass, options = {})
@@ -89,63 +73,12 @@ def self.build(klass, options = {})
else
builder = @@builders[UIView]
end
- builder.call(klass, options)
- end
-
- def self.register(klass, proc)
- @@builders[klass] = proc
- end
-
- private
-
- def self.create_ui_view(klass, options = {})
- klass.alloc.initWithFrame(CGRectZero)
- end
-
- def self.create_ui_control(klass, options = {})
- klass.alloc.init
- end
-
- def self.create_ui_activity_indicator_view(klass, options = {})
- style = options.delete(:style) || UIActivityIndicatorViewStyleWhite
- UIActivityIndicatorView.alloc.initWithActivityIndicatorStyle(style)
- end
-
- def self.create_ui_button(klass, options = {})
- button_type = options.delete(:buttonType) || UIButtonTypeRoundedRect
- UIButton.buttonWithType(button_type)
- end
-
- def self.create_ui_image_view(klass, options = {})
- image = options.delete(:image)
- highlighted_image = options.delete(:highlightedImage)
- if image && highlighted_image
- UIImageView.alloc.initWithImage(image, highlightedImage:highlighted_image)
- elsif image
- UIImageView.alloc.initWithImage(image)
- else
- UIImageView.alloc.initWithFrame(CGRectZero)
- end
- end
-
- def self.create_ui_progress_view(klass, options = {})
- style = options.delete(:style) || UIProgressViewStyleDefault
- UIProgressView.alloc.initWithProgressViewStyle(style)
- end
-
- def self.create_ui_segmented_control(klass, options = {})
- items = options.delete(:items) || []
- UISegmentedControl.alloc.initWithItems(items)
- end
-
- def self.create_ui_table_view(klass, options = {})
- style = options.delete(:style) || UITableViewStylePlain
- UITableView.alloc.initWithFrame(CGRectZero, style: style)
+
+ builder.build(klass, options)
end
- def self.create_ui_table_view_cell(klass, options = {})
- style = options.delete(:style) || UITableViewCellStyleDefault
- UITableViewCell.alloc.initWithStyle(style, reuseIdentifier: options[:reuseIdentifier])
+ def self.register(klass, builder)
+ @@builders[klass] = builder
end
end
end
View
Binary file not shown.
@@ -0,0 +1,12 @@
+describe "UIActivityIndicatorViewBuilder" do
+ it "should build UIActivityIndicatorView" do
+ view = UI::UIActivityIndicatorViewBuilder.new.build(UIActivityIndicatorView)
+ view.class.should == UIActivityIndicatorView
+ view.activityIndicatorViewStyle.should == UIActivityIndicatorViewStyleWhite
+ end
+
+ it "should build UIActivityIndicatorView with style" do
+ view = UI::UIActivityIndicatorViewBuilder.new.build(UIActivityIndicatorView, style: UIActivityIndicatorViewStyleGray)
+ view.activityIndicatorViewStyle.should == UIActivityIndicatorViewStyleGray
+ end
+end
@@ -0,0 +1,12 @@
+describe "UIButtonBuilder" do
+ it "should build UIButton" do
+ button = UI::UIButtonBuilder.new.build(UIButton)
+ button.class.should == UIRoundedRectButton
+ button.buttonType.should == UIButtonTypeRoundedRect
+ end
+
+ it "should build UIButton with buttonType" do
+ button = UI::UIButtonBuilder.new.build(UIButton, buttonType: UIButtonTypeDetailDisclosure)
+ button.buttonType.should == UIButtonTypeDetailDisclosure
+ end
+end
@@ -0,0 +1,5 @@
+describe "UIControlBuilder" do
+ it "should build UIControl" do
+ UI::UIControlBuilder.new.build(UIControl).class.should == UIControl
+ end
+end
Oops, something went wrong.

0 comments on commit 155c147

Please sign in to comment.