Class: UIViewController

Inherits:
Object
  • Object
show all
Includes:
Teacup::Layout
Defined in:
lib/teacup/z_core_extensions/ui_view_controller.rb

Overview

Adds methods to the UIViewController class to make defining a layout and stylesheet very easy. Also provides rotation methods that analyze

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Teacup::Layout

#layout, #stylesheet, #subview

Class Attribute Details

.layout_definitionObject (readonly)

Returns the value of attribute layout_definition.



7
8
9
# File 'lib/teacup/z_core_extensions/ui_view_controller.rb', line 7

def layout_definition
  @layout_definition
end

Class Method Details

.layout(stylename = nil, properties = {}, &block) ⇒ Object

Define the layout of a controller’s view.

This function is analogous to Teacup::Layout#layout, though it is designed so you can create an entire layout in a declarative manner in your controller.

The hope is that this declarativeness will allow us to automatically deal with common iOS programming tasks (like releasing views when low-memory conditions occur) for you. This is still not implemented though.

Examples:

MyViewController < UIViewController
  layout :my_view do
    subview UILabel, title: "Test"
    subview UITextField, {
      frame: [[200, 200], [100, 100]]
      delegate: self
    }
    subview UIView, :shiny_thing) {
      subview UIView, :centre_of_shiny_thing
    }
  end
end

Parameters:

  • name

    The stylename for your controller’s view.

  • properties (defaults to: {})

    Any extra styles that you want to apply.

  • &block

    The block in which you should define your layout. It will be instance_exec’d in the context of a controller instance.



42
43
44
# File 'lib/teacup/z_core_extensions/ui_view_controller.rb', line 42

def layout(stylename=nil, properties={}, &block)
  @layout_definition = [stylename, properties, block]
end

.stylesheet(new_stylesheet = nil) ⇒ Object



46
47
48
49
50
51
52
# File 'lib/teacup/z_core_extensions/ui_view_controller.rb', line 46

def stylesheet(new_stylesheet=nil)
  if new_stylesheet.nil?
    return @stylesheet
  end

  @stylesheet = new_stylesheet
end

Instance Method Details

#auto(layout_view = self.view, layout_subviews = {}, &layout_block) ⇒ Object

Calling this method uses Nick Quaranto’s motion-layout gem to provide ASCII art style access to autolayout. It assigns all the subviews by stylename, and assigns ‘self.view` as the target view. Beyond that, it’s up to you to implement the layout methods:

auto do
  metrics 'margin' => 20
  vertical "|-[top]-margin-[bottom]-|"
  horizontal "|-margin-[top]-margin-|"
  horizontal "|-margin-[bottom]-margin-|"
end


240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
# File 'lib/teacup/z_core_extensions/ui_view_controller.rb', line 240

def auto(layout_view=self.view, layout_subviews={}, &layout_block)
  raise "gem install 'motion-layout'" unless defined? Motion::Layout

  Teacup.get_subviews(self.view).each do |view|
    if view.stylename && ! layout_subviews[view.stylename.to_s]
      layout_subviews[view.stylename.to_s] = view
    end
  end

  Motion::Layout.new do |layout|
    layout.view layout_view
    layout.subviews layout_subviews
    layout.instance_eval(&layout_block)
  end
end

#autorotateMaskObject

You can use this method in ‘supportedInterfaceOrientations`, and it will query the stylesheet for the supported orientations, based on what orientations are defined. At a minimum, to opt-in to this feature, you’ll need to define styles like ‘style :root, landscape: true`



174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/teacup/z_core_extensions/ui_view_controller.rb', line 174

def autorotateMask
  device = UIDevice.currentDevice.userInterfaceIdiom
  if view.stylesheet and view.stylesheet.is_a?(Teacup::Stylesheet) and view.stylename
    properties = view.stylesheet.query(view.stylename, self, orientation)

    orientations = 0
    if properties.supports?(:portrait) or properties.supports?(:upside_up)
      orientations |= UIInterfaceOrientationPortrait
    end

    if device == UIUserInterfaceIdiomPhone
      # :portrait does not imply upside_down on the iphone
      if properties.supports?(:upside_down)
        orientations |= UIInterfaceOrientationPortraitUpsideDown
      end
    else
      # but does on the ipad
      if properties.supports?(:portrait) or properties.supports?(:upside_down)
        orientations |= UIInterfaceOrientationPortraitUpsideDown
      end
    end

    if properties.supports?(:landscape) or properties.supports?(:landscape_left)
      orientations |= UIInterfaceOrientationLandscapeLeft
    end

    if properties.supports?(:landscape) or properties.supports?(:landscape_right)
      orientations |= UIInterfaceOrientationLandscapeRight
    end

    if orientations == 0
      orientations |= UIInterfaceOrientationPortrait
    end
    return orientations
  end

  # returns the system default
  if device == UIUserInterfaceIdiomPhone
    return UIInterfaceOrientationMaskAllButUpsideDown
  else
    return UIInterfaceOrientationMaskAll
  end
end

#autorotateToOrientation(orientation) ⇒ Object

This method used to be useful for the ‘shouldAutorotateToOrientation` method, but the iOS 6 update deprecates that method. Instead, use the `supportedInterfaceOrientations` and return `autorotateMask`.



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/teacup/z_core_extensions/ui_view_controller.rb', line 131

def autorotateToOrientation(orientation)
  if view.stylesheet and view.stylesheet.is_a?(Teacup::Stylesheet) and view.stylename
    properties = view.stylesheet.query(view.stylename, self, orientation)

    # check for orientation-specific properties
    case orientation
    when UIInterfaceOrientationPortrait
      # portrait is "on" by default, must be turned off explicitly
      if properties.supports?(:portrait) == nil and properties.supports?(:upside_up) == nil
        return true
      end

      return (properties.supports?(:portrait) or properties.supports?(:upside_up))
    when UIInterfaceOrientationPortraitUpsideDown
      if UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPhone
        # iphone must have an explicit upside-down style, otherwise this returns
        # false
        return properties.supports?(:upside_down)
      else
        # ipad can just have a portrait style
        return (properties.supports?(:portrait) or properties.supports?(:upside_down))
      end
    when UIInterfaceOrientationLandscapeLeft
      return (properties.supports?(:landscape) or properties.supports?(:landscape_left))
    when UIInterfaceOrientationLandscapeRight
      return (properties.supports?(:landscape) or properties.supports?(:landscape_right))
    end

    return false
  end

  # returns the system default
  if device == UIUserInterfaceIdiomPhone
    return orientation != UIInterfaceOrientationPortraitUpsideDown
  else
    return true
  end
end

#layoutDidLoadObject



124
125
126
# File 'lib/teacup/z_core_extensions/ui_view_controller.rb', line 124

def layoutDidLoad
  true
end

#stylesheet=(new_stylesheet) ⇒ Object

Assigning a new stylesheet triggers restyle!.

Assigning a stylesheet is an alternative to returning a Stylesheet in the stylesheet method. Note that restyle! calls stylesheet, so while assigning a stylesheet will trigger restyle!, your stylesheet will not be picked up if you don’t return it in a custom stylesheet method.

Examples:


stylesheet = Teacup::Stylesheet[:ipadhorizontal]
stylesheet = :ipadhorizontal

Returns:

  • Teacup::Stylesheet



69
70
71
72
73
74
# File 'lib/teacup/z_core_extensions/ui_view_controller.rb', line 69

def stylesheet=(new_stylesheet)
  super
  if self.viewLoaded?
    self.view.restyle!
  end
end

#top_level_viewObject



76
77
78
# File 'lib/teacup/z_core_extensions/ui_view_controller.rb', line 76

def top_level_view
  return self.view
end

#viewDidLoadObject

Instantiate the layout from the class, and then call layoutDidLoad.

If you want to use Teacup in your controller, please hook into layoutDidLoad, not viewDidLoad.



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/teacup/z_core_extensions/ui_view_controller.rb', line 85

def viewDidLoad
  # look for a layout_definition in the list of ancestors
  layout_definition = nil
  my_stylesheet = self.stylesheet
  parent_class = self.class
  while parent_class != NSObject and not (layout_definition && my_stylesheet)
    if not my_stylesheet and parent_class.respond_to?(:stylesheet)
      my_stylesheet = parent_class.stylesheet
    end

    if not layout_definition and parent_class.respond_to?(:layout_definition)
      layout_definition = parent_class.layout_definition
    end
    parent_class = parent_class.superclass
  end

  should_restyle = Teacup.should_restyle_and_block

  if my_stylesheet and not self.stylesheet
    self.stylesheet = my_stylesheet
  end

  if layout_definition
    stylename, properties, block = layout_definition
    layout(view, stylename, properties, &block)
  end

  if should_restyle
    Teacup.should_restyle!
    self.view.restyle!
  end

  if defined? NSLayoutConstraint
    self.view.apply_constraints
  end

  layoutDidLoad
end

#willAnimateRotationToInterfaceOrientation(orientation, duration: duration) ⇒ Object

restyles the view! be careful about putting styles in your stylesheet that you change in your controller. anything that might change over time should be applied in your controller using ‘style`



221
222
223
# File 'lib/teacup/z_core_extensions/ui_view_controller.rb', line 221

def willAnimateRotationToInterfaceOrientation(orientation, duration:duration)
  view.restyle!(orientation)
end