Class: UIView

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

Overview

Methods to retrieve a subview using the stylename as a key Kinda similar to jQuery-style $(el).find(‘stylename’)

Direct Known Subclasses

CustomView, DummyView

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Teacup::Layout

#layout, #subview

Instance Attribute Details

#debugObject

Enable debug messages for this object



17
18
19
# File 'lib/teacup/z_core_extensions/ui_view.rb', line 17

def debug
  @debug
end

#stylenameObject

The current stylename that is used to look up properties in the stylesheet.



10
11
12
# File 'lib/teacup/z_core_extensions/ui_view.rb', line 10

def stylename
  @stylename
end

#teacup_next_responderObject

Any class that includes Teacup::Layout gets a ‘layout` method, which assigns itself as the ’teacup_next_responder’.



14
15
16
# File 'lib/teacup/z_core_extensions/ui_view.rb', line 14

def teacup_next_responder
  @teacup_next_responder
end

Instance Method Details

#_teacup_check_stylename(name_or_class) ⇒ Object



47
48
49
50
51
52
53
54
55
56
# File 'lib/teacup/z_core_extensions/ui_view_getters.rb', line 47

def _teacup_check_stylename(name_or_class)
  if name_or_class.is_a? Class
    return self.is_a?(name_or_class)
  elsif stylename == name_or_class
    return true
  elsif stylesheet.is_a?(Teacup::Stylesheet)
    return stylesheet.extends_style?(self.stylename, name_or_class)
  end
  return false
end

#add_uniq_constraints(constraint) ⇒ Object



244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
# File 'lib/teacup/z_core_extensions/ui_view.rb', line 244

def add_uniq_constraints(constraint)
  @teacup_constraints ||= {}

  if constraint.is_a? Array
    constraint.each { |constraint|
      add_uniq_constraints(constraint)
    }
  elsif constraint.is_a? Hash
    constraint.each { |sym, relative_to|
      @teacup_constraints[sym] = relative_to
    }
  elsif constraint.is_a?(Teacup::Constraint) || constraint.is_a?(Symbol)
    @teacup_constraints[constraint] = true
  else
    raise "Unsupported constraint: #{constraint.inspect}"
  end
end

#animate_to_style(style) ⇒ Object

Animate a change to new styles

This is equivalent to wrapping a call to .style() inside UIView.beginAnimations.

Parameters:

  • Hash

    the new styles and options for the animation



207
208
209
210
211
212
213
214
# File 'lib/teacup/z_core_extensions/ui_view.rb', line 207

def animate_to_style(style)
  UIView.beginAnimations(nil, context: nil)
  UIView.setAnimationDuration(style[:duration]) if style[:duration]
  UIView.setAnimationCurve(style[:curve]) if style[:curve]
  UIView.setAnimationDelay(style[:delay]) if style[:delay]
  style(style)
  UIView.commitAnimations
end

#animate_to_stylename(stylename, options = {}) ⇒ Object

Animate a change to a new stylename.

This is equivalent to wrapping a call to .stylename= inside UIView.beginAnimations.

Parameters:

  • Symbol

    the new stylename

  • Options

    the options for the animation (may include the duration and the curve)



188
189
190
191
192
193
194
195
196
197
198
# File 'lib/teacup/z_core_extensions/ui_view.rb', line 188

def animate_to_stylename(stylename, options={})
  return if self.stylename == stylename

  UIView.beginAnimations(nil, context: nil)
  # TODO: This should be in a style-sheet!
  UIView.setAnimationDuration(options[:duration]) if options[:duration]
  UIView.setAnimationCurve(options[:curve]) if options[:curve]
  UIView.setAnimationDelay(options[:delay]) if options[:delay]
  self.stylename = stylename
  UIView.commitAnimations
end

#apply_constraintsObject



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/teacup/z_core_extensions/ui_view.rb', line 161

def apply_constraints
  if @teacup_added_constraints
    @teacup_added_constraints.each do |constraint|
      self.removeConstraint(constraint)
    end
  end
  @teacup_added_constraints = nil
  all_constraints = get_ns_constraints

  return if all_constraints.empty?

  @teacup_added_constraints = []
  all_constraints.each do |ns_constraint|
    @teacup_added_constraints << ns_constraint
    self.addConstraint(ns_constraint)
  end
end

#get_ns_constraintsObject



83
84
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
123
124
125
126
127
128
129
130
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
# File 'lib/teacup/z_core_extensions/ui_view.rb', line 83

def get_ns_constraints
  # gets the array of Teacup::Constraint objects
  my_constraints = (@teacup_constraints || []).map { |constraint, relative_to|
    if constraint.is_a?(Teacup::Constraint)
      constraint
    else
      if relative_to == true
        Teacup::Constraint.from_sym(constraint)
      else
        Teacup::Constraint.from_sym(constraint, relative_to)
      end
    end
  }.flatten.tap{ |my_constraints|
    unless my_constraints.empty?
      self.setTranslatesAutoresizingMaskIntoConstraints(false)
    end
  }.map do |original_constraint|
    constraint = original_constraint.copy

    case original_constraint.target
    when UIView
      constraint.target = original_constraint.target
    when :self
      constraint.target = self
    when :superview
      constraint.target = self.superview
    when Symbol, String
      container = self
      constraint.target = nil
      while container && constraint.target.nil?
        constraint.target = container.viewWithStylename(original_constraint.target)
        container = container.superview
      end
    end

    case original_constraint.relative_to
    when nil
      constraint.relative_to = nil
    when UIView
      constraint.relative_to = original_constraint.relative_to
    when :self
      constraint.relative_to = self
    when :superview
      constraint.relative_to = self.superview
    when Symbol, String
      # TODO: this re-checks lots of views - everytime it goes up to the
      # superview, it checks all the leaves again.
      container = self
      constraint.relative_to = nil
      while container && constraint.relative_to.nil?
        constraint.relative_to = container.viewWithStylename(original_constraint.relative_to)
        container = container.superview
      end
    end

    if original_constraint.relative_to && ! constraint.relative_to
      puts "Could not find #{original_constraint.relative_to.inspect}"
      container = self
      tab = '  '
      while container && constraint.relative_to.nil?
        tab << '->'
        puts "#{tab} #{container.stylename.inspect}"
        container = container.superview
      end
    end

    # the return value, for the map
    constraint.nslayoutconstraint
  end

  # now add all che child constraints
  subviews.each do |subview|
    my_constraints.concat(subview.get_ns_constraints)
  end

  my_constraints
end

#restyle!(orientation = nil) ⇒ Object



74
75
76
77
78
79
80
81
# File 'lib/teacup/z_core_extensions/ui_view.rb', line 74

def restyle!(orientation=nil)
  if Teacup.should_restyle?
    if stylesheet && stylesheet.is_a?(Teacup::Stylesheet)
      style(stylesheet.query(stylename, self, orientation))
    end
    subviews.each{ |subview| subview.restyle!(orientation) }
  end
end

#style(properties) ⇒ Object

Apply style properties to this element.

Takes a hash of properties such as may have been read from a stylesheet or passed as parameters to Teacup::Layout#layout, and applies them to the element.

Does a little bit of magic (that may be split out as ‘sugarcube’) to make properties work as you’d expect.

If you try and assign something in properties that is not supported, a warning message will be emitted.

Parameters:

  • Hash

    the properties to set.



229
230
231
232
233
234
235
236
237
238
# File 'lib/teacup/z_core_extensions/ui_view.rb', line 229

def style(properties)
  if properties.key?(:constraints)
    add_uniq_constraints(properties.delete(:constraints))
  end

  Teacup.apply_hash self, properties

  self.setNeedsDisplay
  self.setNeedsLayout
end

#stylesheetObject



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/teacup/z_core_extensions/ui_view.rb', line 50

def stylesheet
  if @stylesheet.is_a? Symbol
    @stylesheet = Teacup::Stylesheet[@stylesheet]
  end
  # is a stylesheet assigned explicitly?
  retval = @stylesheet
  return retval if retval

  # the 'teacup_next_responder' is assigned in the `layout` method, and links
  # any views created there to the custom class (could be a controller, could
  # be any class that includes Teacup::Layout).  That responder is checked
  # next, but only if it wouldn't result in a circular loop.
  if ! retval && @teacup_next_responder && teacup_next_responder != self
    retval = @teacup_next_responder.stylesheet
  end

  # lastly, go up the chain; either a controller or superview
  if ! retval && nextResponder && nextResponder.respond_to?(:stylesheet)
    retval = nextResponder.stylesheet
  end

  return retval
end

#stylesheet=(new_stylesheet) ⇒ Object

Alter the stylesheet of this view.

This will cause new styles to be applied using the current stylename, and will recurse into subviews.

If you would prefer that a given UIView object does not inherit the stylesheet from its parents, override the ‘stylesheet’ method to return the correct value at all times.

Parameters:

  • Teacup::Stylesheet

    stylesheet.



39
40
41
42
43
44
45
46
47
48
# File 'lib/teacup/z_core_extensions/ui_view.rb', line 39

def stylesheet=(new_stylesheet)
  should_restyle = Teacup.should_restyle_and_block

  @stylesheet = new_stylesheet

  if should_restyle
    Teacup.should_restyle!
    restyle!
  end
end

#top_level_viewObject



240
241
242
# File 'lib/teacup/z_core_extensions/ui_view.rb', line 240

def top_level_view
  return self
end

#viewsWithStylename(name_or_class) ⇒ Object

get all subviews by stylename or class my_view.viewsWithStylename :button => [#<UIButton..>, #<UIButton…>] my_view.viewsWithStylename UIButton => [#<UIButton..>, #<UIButton…>]



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/teacup/z_core_extensions/ui_view_getters.rb', line 27

def viewsWithStylename name_or_class
  retval = []
  retval << self if self._teacup_check_stylename(name_or_class)

  search_views = [].concat(self.subviews)
  # ewww, a traditional for loop! the search_views array is modified in place,
  # and `each` and other methods don't like that.
  index = 0
  while index < search_views.length
    view = search_views[index]
    if view._teacup_check_stylename(name_or_class)
      retval << view
    end
    search_views.concat(view.subviews)
    index += 1
  end

  return retval
end

#viewWithStylename(name_or_class) ⇒ Object

get one subview by stylename or class. If the receiver matches, it will be returned my_view.viewWithStylename :button => #<UIButton..> my_view.viewWithStylename UIButton => #<UIButton..>



9
10
11
12
13
14
15
16
17
18
19
20
21
22
# File 'lib/teacup/z_core_extensions/ui_view_getters.rb', line 9

def viewWithStylename name_or_class
  return self if self._teacup_check_stylename(name_or_class)

  view = subviews.find { |view| view._teacup_check_stylename(name_or_class) }
  return view if view

  # found_subview will get assigned to the view we want, but the subview is
  # what is returned.
  found_subview = nil
  view = subviews.find { |subview| found_subview = subview.viewWithStylename(name_or_class) }
  return found_subview if view

  return nil  # couldn't find it
end