Class: MotionPrime::BaseElement

Inherits:
Object
  • Object
show all
Extended by:
HasClassFactory
Includes:
HasClassFactory, HasNormalizer, HasStyleChainBuilder, HasStyleOptions, MotionSupport::Callbacks
Defined in:
motion-prime/elements/base_element.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from HasClassFactory

camelize_factory, class_factory, low_camelize_factory, underscore_factory

Methods included from HasStyleOptions

#extract_font_from

Methods included from HasStyleChainBuilder

#build_styles_chain

Methods included from HasNormalizer

#debug_info, #element?, #normalize_object, #normalize_options, #normalize_value

Constructor Details

#initialize(options = {}) ⇒ BaseElement

Returns a new instance of BaseElement.



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'motion-prime/elements/base_element.rb', line 22

def initialize(options = {})
  options[:screen] = options[:screen].try(:weak_ref)
  @options = options
  @screen = options[:screen]
  @section = options[:section]

  @view_class = options[:view_class] || 'UIView'
  @name = options[:name]
  @block = options[:block]
  @view_name = underscore_factory(self.class_name_without_kvo.demodulize).gsub(/(_draw)?_element/, '')

  if Prime.env.development?
    info = []
    info << @name
    info << view_name
    info << section.try(:name)
    info << screen.class
    @_element_info = info.join(' ')
    @@_allocated_elements ||= []
    @@_allocated_elements << @_element_info
  end
end

Instance Attribute Details

#nameObject

Returns the value of attribute name.



17
18
19
# File 'motion-prime/elements/base_element.rb', line 17

def name
  @name
end

#optionsObject

Returns the value of attribute options.



17
18
19
# File 'motion-prime/elements/base_element.rb', line 17

def options
  @options
end

#screenObject

Returns the value of attribute screen.



17
18
19
# File 'motion-prime/elements/base_element.rb', line 17

def screen
  @screen
end

#sectionObject

Returns the value of attribute section.



17
18
19
# File 'motion-prime/elements/base_element.rb', line 17

def section
  @section
end

#stylesObject

Returns the value of attribute styles.



17
18
19
# File 'motion-prime/elements/base_element.rb', line 17

def styles
  @styles
end

#viewObject

Returns the value of attribute view.



17
18
19
# File 'motion-prime/elements/base_element.rb', line 17

def view
  @view
end

#view_classObject

Returns the value of attribute view_class.



17
18
19
# File 'motion-prime/elements/base_element.rb', line 17

def view_class
  @view_class
end

#view_nameObject

Returns the value of attribute view_name.



17
18
19
# File 'motion-prime/elements/base_element.rb', line 17

def view_name
  @view_name
end

Class Method Details

.after_render(method_name) ⇒ Object



280
281
282
# File 'motion-prime/elements/base_element.rb', line 280

def after_render(method_name)
  set_callback :render, :after, method_name
end

.before_render(method_name) ⇒ Object



277
278
279
# File 'motion-prime/elements/base_element.rb', line 277

def before_render(method_name)
  set_callback :render, :before, method_name
end

.factory(type, options = {}) ⇒ Object



270
271
272
273
274
275
276
# File 'motion-prime/elements/base_element.rb', line 270

def factory(type, options = {})
  element_class = class_factory("#{type}_element", true) || self
  view_class_name = camelize_factory("ui_#{type}")

  options.merge!(view_class: view_class_name)
  element_class.new(options)
end

Instance Method Details

#add_target(target = nil, action = 'on_click:', event = :touch) ⇒ Object



54
55
56
57
# File 'motion-prime/elements/base_element.rb', line 54

def add_target(target = nil, action = 'on_click:', event = :touch)
  return false unless self.view
  self.view.addTarget(target || section, action: action, forControlEvents: event.uicontrolevent)
end

#bind_gesture(action, receiver = nil) ⇒ Object



153
154
155
156
157
158
# File 'motion-prime/elements/base_element.rb', line 153

def bind_gesture(action, receiver = nil)
  receiver ||= self
  single_tap = UITapGestureRecognizer.alloc.initWithTarget(receiver, action: action)
  view.addGestureRecognizer single_tap
  view.setUserInteractionEnabled true
end

#cell_element?Boolean

Returns:

  • (Boolean)


164
165
166
# File 'motion-prime/elements/base_element.rb', line 164

def cell_element?
  @view_class == 'UICollectionViewCell' || @view_class == 'UITableViewCell'
end

#cell_section?Boolean

Returns:

  • (Boolean)


160
161
162
# File 'motion-prime/elements/base_element.rb', line 160

def cell_section?
  section.respond_to?(:cell_section_name)
end

#compute_options!Object



91
92
93
94
95
96
97
98
99
100
101
102
# File 'motion-prime/elements/base_element.rb', line 91

def compute_options!
  block_options = compute_block_options || {}
  raw_options = self.options.except(:screen, :name, :block, :view_class).merge(block_options)
  compute_style_options(raw_options)
  raw_options = Styles.for(styles).deep_merge(raw_options)
  @computed_options = raw_options
  normalize_options(@computed_options, section.try(:elements_eval_object), %w[
    font font_name font_size text placeholder title_label
    padding padding_left padding_right padding_top padding_bottom
    left right min_width min_outer_width max_width max_outer_width width
    top bottom min_height min_outer_height max_height max_outer_height height])
end

#computed_optionsObject

Lazy-computing options



86
87
88
89
# File 'motion-prime/elements/base_element.rb', line 86

def computed_options
  compute_options! unless @computed_options
  @computed_options
end

#deallocObject



45
46
47
48
49
50
51
52
# File 'motion-prime/elements/base_element.rb', line 45

def dealloc
  if Prime.env.development?
    index = @@_allocated_elements.index(@_element_info)
    @@_allocated_elements.delete_at(index) if index
  end
  Prime.logger.dealloc_message :element, self, self.name
  super
end

#hideObject



145
146
147
# File 'motion-prime/elements/base_element.rb', line 145

def hide
  view.hidden = true if view # TODO: should we update computed options in opposite case?
end

#notify_section_after_renderObject



63
64
65
# File 'motion-prime/elements/base_element.rb', line 63

def notify_section_after_render
  section.try(:after_element_render, self)
end

#notify_section_before_renderObject



59
60
61
# File 'motion-prime/elements/base_element.rb', line 59

def notify_section_before_render
  section.try(:before_element_render, self)
end

#reload!Object



104
105
106
107
# File 'motion-prime/elements/base_element.rb', line 104

def reload!
  reset_computed_values
  compute_options!
end

#render(options = {}, &block) ⇒ Object



67
68
69
70
71
# File 'motion-prime/elements/base_element.rb', line 67

def render(options = {}, &block)
  run_callbacks :render do
    render!(options, &block)
  end
end

#render!(options = {}, &block) ⇒ Object



73
74
75
76
77
78
79
80
81
82
83
# File 'motion-prime/elements/base_element.rb', line 73

def render!(options = {}, &block)
  view = screen.add_view class_factory(view_class), computed_options.merge(options) do |view|
    @view = view
    block.try(:call, view, self)
  end

  if computed_options.has_key?(:delegate) && computed_options[:delegate].respond_to?(:delegated_by) && view.respond_to?(:setDelegate)
    computed_options[:delegate].delegated_by(view)
  end
  view
end

#rerender!(changed_options = []) ⇒ Object



109
110
111
112
113
114
115
116
117
# File 'motion-prime/elements/base_element.rb', line 109

def rerender!(changed_options = [])
  render_target = view.try(:superview)
  view.try(:removeFromSuperview)
  render(render_target: render_target)

  if (changed_options & [:text, :size_to_fit]).any? && respond_to?(:size_to_fit)
    size_to_fit
  end
end

#showObject



149
150
151
# File 'motion-prime/elements/base_element.rb', line 149

def show
  view.hidden = false if view
end

#updateObject



141
142
143
# File 'motion-prime/elements/base_element.rb', line 141

def update
  update_with_options({})
end

#update_options(new_options) ⇒ Object



126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'motion-prime/elements/base_element.rb', line 126

def update_options(new_options)
  options.deep_merge!(new_options)
  return unless view

  required_options = if new_options.slice(:width, :height, :top, :left, :right, :bottom).any?
    new_options[:calculate_frame] = true
    [:width, :height, :top, :left, :right, :bottom]
  elsif new_options.slice(:text, :title).any?
    [:line_spacing, :line_height, :underline, :fragment_color, :text_alignment, :font, :font_name, :font_size, :line_break_mode, :number_of_lines]
  end
  new_options = computed_options.slice(*Array.wrap(required_options)).merge(new_options)

  ViewStyler.new(view, view.superview.try(:bounds), new_options).apply
end

#update_with_options(new_options = {}) ⇒ Object



119
120
121
122
123
124
# File 'motion-prime/elements/base_element.rb', line 119

def update_with_options(new_options = {})
  options.deep_merge!(new_options)
  reload!
  computed_options.deep_merge!(new_options)
  rerender!(new_options.keys)
end