motion-prime 0.4.3 → 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +6 -14
  2. data/CHANGELOG.md +5 -0
  3. data/Gemfile.lock +1 -1
  4. data/ROADMAP.md +9 -4
  5. data/doc/code/getting_started.rb +1 -2
  6. data/doc/code/screens.rb +54 -0
  7. data/doc/docs/getting_started.html +27 -6
  8. data/doc/docs/screens.html +166 -0
  9. data/files/Gemfile +1 -1
  10. data/files/Gemfile.lock +64 -0
  11. data/files/app/environment.rb +10 -0
  12. data/files/app/styles/sidebar.rb +3 -10
  13. data/files/resources/images/menu_button.png +0 -0
  14. data/files/resources/images/menu_button@2x.png +0 -0
  15. data/motion-prime/app_delegate.rb +19 -0
  16. data/motion-prime/core_ext/kernel.rb +4 -0
  17. data/motion-prime/elements/_content_text_mixin.rb +23 -11
  18. data/motion-prime/elements/_text_mixin.rb +54 -0
  19. data/motion-prime/elements/base_element.rb +19 -14
  20. data/motion-prime/elements/draw.rb +22 -1
  21. data/motion-prime/elements/draw/_draw_background_mixin.rb +28 -28
  22. data/motion-prime/elements/draw/image.rb +67 -48
  23. data/motion-prime/elements/draw/label.rb +59 -49
  24. data/motion-prime/elements/draw/view.rb +5 -3
  25. data/motion-prime/helpers/has_style_chain_builder.rb +1 -3
  26. data/motion-prime/models/association_collection.rb +8 -0
  27. data/motion-prime/models/finder.rb +8 -0
  28. data/motion-prime/mp.rb +4 -0
  29. data/motion-prime/screens/_navigation_mixin.rb +4 -0
  30. data/motion-prime/screens/base_screen.rb +7 -0
  31. data/motion-prime/screens/sidebar_container_screen.rb +2 -2
  32. data/motion-prime/sections/_cell_section_mixin.rb +44 -5
  33. data/motion-prime/sections/_draw_section_mixin.rb +120 -0
  34. data/motion-prime/sections/base_section.rb +29 -24
  35. data/motion-prime/sections/form.rb +48 -65
  36. data/motion-prime/sections/form/base_field_section.rb +2 -2
  37. data/motion-prime/sections/table.rb +143 -82
  38. data/motion-prime/sections/table/table_delegate.rb +48 -0
  39. data/motion-prime/styles/form.rb +1 -1
  40. data/motion-prime/support/mp_cell_with_section.rb +6 -2
  41. data/motion-prime/support/mp_view_with_section.rb +1 -1
  42. data/motion-prime/version.rb +1 -1
  43. data/motion-prime/views/_frame_calculator_mixin.rb +4 -8
  44. data/motion-prime/views/layout.rb +1 -0
  45. data/motion-prime/views/view_styler.rb +3 -12
  46. metadata +34 -26
  47. data/motion-prime/sections/_draw_mixin.rb +0 -66
@@ -1,16 +1,16 @@
1
1
  Prime::Styles.define :sidebar do
2
2
  style :screen,
3
- background_color: :clear
3
+ background_color: proc { Prime::Config.color.dark }
4
4
  style :table,
5
5
  top: 150,
6
6
  left: 0,
7
7
  width: 320,
8
8
  bottom: 0,
9
- background_color: :clear,
9
+ background_color: proc { Prime::Config.color.dark },
10
10
  separator_color: :clear
11
11
 
12
12
  style :table_cell,
13
- selection_style: UITableViewCellSelectionStyleNone
13
+ selection_style: :none
14
14
 
15
15
  style :action_title,
16
16
  text_color: :white,
@@ -20,11 +20,4 @@ Prime::Styles.define :sidebar do
20
20
  size_to_fit: true,
21
21
  left: 20,
22
22
  text_color: :white
23
-
24
- style :action_arrow,
25
- width: 9,
26
- height: 14,
27
- right: 150,
28
- top: 17,
29
- image: "images/sidebar/arrow.png"
30
23
  end
@@ -32,6 +32,7 @@ module MotionPrime
32
32
 
33
33
  # TODO: move to private methods
34
34
  def open_root_screen(screen)
35
+ close_current_screens
35
36
  screen.send(:on_screen_load) if screen.respond_to?(:on_screen_load)
36
37
  screen.wrap_in_navigation if screen.respond_to?(:wrap_in_navigation)
37
38
 
@@ -46,6 +47,7 @@ module MotionPrime
46
47
  # TODO: move to private methods
47
48
  def open_content_screen(screen)
48
49
  if sidebar?
50
+ close_current_screens
49
51
  sidebar_container.content_controller = screen
50
52
  else
51
53
  open_root_screen(screen)
@@ -83,7 +85,24 @@ module MotionPrime
83
85
  NSNotificationCenter.defaultCenter.postNotificationName(:on_current_user_reset, object: user_was)
84
86
  end
85
87
 
88
+ def close_screens(screens)
89
+ Array.wrap(screens).each { |screen| screen.on_destroy if screen.respond_to?(:on_destroy) }
90
+ end
91
+
86
92
  private
93
+ def close_current_screens
94
+ return unless self.window
95
+
96
+ screens = if sidebar? && sidebar_container.content_controller.is_a?(UINavigationController)
97
+ sidebar_container.content_controller.childViewControllers
98
+ elsif sidebar?
99
+ sidebar_container.content_controller
100
+ else
101
+ window.rootViewController
102
+ end
103
+ close_screens(screens)
104
+ end
105
+
87
106
  def create_tab_bar(screens)
88
107
  MotionPrime::TabBarController.new(screens)
89
108
  end
@@ -6,4 +6,8 @@ class Kernel
6
6
  def class_name_without_kvo
7
7
  self.class.name.gsub(/^NSKVONotifying_/, '')
8
8
  end
9
+
10
+ def weak_ref
11
+ WeakRef.new(self)
12
+ end
9
13
  end
@@ -1,5 +1,8 @@
1
+ motion_require './_text_mixin.rb'
1
2
  module MotionPrime
2
3
  module ElementContentTextMixin
4
+ include ElementTextMixin
5
+
3
6
  def content_text
4
7
  is_a?(ButtonElement) ? button_content_text : input_content_text
5
8
  end
@@ -8,6 +11,21 @@ module MotionPrime
8
11
  (is_a?(ButtonElement) ? button_content_font : input_content_font) || :system.uifont
9
12
  end
10
13
 
14
+ def content_attributed_text
15
+ if view.try(:is_a?, UITextView) && view.text.present?
16
+ text = view.attributedText
17
+ text += ' ' if text.to_s.end_with?("\n") # does not respect \n at the end by default
18
+ return text
19
+ end
20
+
21
+ options = {
22
+ text: content_text,
23
+ font: content_font,
24
+ line_spacing: computed_options[:line_spacing]
25
+ }
26
+ computed_options[:html].present? ? html_string(options) : attributed_string(options)
27
+ end
28
+
11
29
  def content_width
12
30
  min, max = computed_options[:min_width].to_f, computed_options[:max_width]
13
31
  return min if content_text.blank?
@@ -23,7 +41,7 @@ module MotionPrime
23
41
  def content_height
24
42
  min, max = computed_options[:min_height].to_f, computed_options[:max_height]
25
43
  return min if content_text.blank?
26
- rect = get_content_rect(computed_options[:width])
44
+ rect = get_content_rect(computed_options[:width] - content_padding_width)
27
45
  @content_height = [[rect.size.height.ceil, max].compact.min, min].max.ceil
28
46
  end
29
47
 
@@ -34,15 +52,9 @@ module MotionPrime
34
52
  private
35
53
  def get_content_rect(width)
36
54
  raise "Please set element width for content size calculation" unless width
37
- attributes = {NSFontAttributeName => content_font }
38
- if computed_options[:line_spacing]
39
- paragrahStyle = NSMutableParagraphStyle.alloc.init
40
- paragrahStyle.setLineSpacing(computed_options[:line_spacing])
41
- attributes[NSParagraphStyleAttributeName] = paragrahStyle
42
- end
43
- attributed_text = NSAttributedString.alloc.initWithString(content_text, attributes: attributes)
44
- attributed_text.boundingRectWithSize(
45
- [width, Float::MAX], options:NSStringDrawingUsesLineFragmentOrigin, context:nil
55
+
56
+ content_attributed_text.boundingRectWithSize(
57
+ [width, Float::MAX], options: NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading | NSStringDrawingTruncatesLastVisibleLine, context:nil
46
58
  )
47
59
  end
48
60
 
@@ -63,7 +75,7 @@ module MotionPrime
63
75
  end
64
76
 
65
77
  def input_value_text
66
- view && !is_a?(DrawElement) ? view.text : computed_options[:text]
78
+ view && !is_a?(DrawElement) ? view.text : (computed_options[:html] || computed_options[:text])
67
79
  end
68
80
 
69
81
  def input_placeholder_text
@@ -0,0 +1,54 @@
1
+ module MotionPrime
2
+ module ElementTextMixin
3
+ # Options
4
+ # text
5
+ # text_color
6
+ # font
7
+ # line_spacing
8
+ # text_alignment
9
+ # text_alignment_name
10
+ # line_break_mode
11
+ # underline (range)
12
+
13
+ def html_string(options)
14
+ styles = []
15
+ styles << "color: #{options[:text_color].hex};" if options[:text_color]
16
+ styles << "line-height: #{options[:line_spacing].to_f + options[:font].pointSize}px;"
17
+ styles << "font-family: '#{options[:font].familyName}';"
18
+ styles << "font-size: #{options[:font].pointSize}px;"
19
+ styles << "text-align: #{options[:text_alignment_name]};" if options[:text_alignment_name]
20
+
21
+ html_options = {
22
+ NSDocumentTypeDocumentAttribute => NSHTMLTextDocumentType,
23
+ NSCharacterEncodingDocumentAttribute => NSNumber.numberWithInt(NSUTF8StringEncoding)
24
+ }
25
+ # DTCoreTextFontDescriptor.setOverrideFontName(Prime::Config.font.light, forFontFamily: 'Calibri', bold: false, italic: false)
26
+ # DTCoreTextFontDescriptor.setOverrideFontName(Prime::Config.font.bold, forFontFamily: 'Calibri', bold: true, italic: false)
27
+ # DTCoreTextFontDescriptor.setOverrideFontName(Prime::Config.font.light_italic, forFontFamily: 'Calibri', bold: false, italic: true)
28
+ # DTCoreTextFontDescriptor.setOverrideFontName(Prime::Config.font.bold_italic, forFontFamily: 'Calibri', bold: true, italic: true)
29
+
30
+ text = "#{options[:text]}<style>* { #{styles.join} }</style>"
31
+ NSAttributedString.alloc.initWithData(text.dataUsingEncoding(NSString.defaultCStringEncoding), options: html_options, documentAttributes: nil, error: nil)
32
+ end
33
+
34
+ def attributed_string(options)
35
+ paragrahStyle = NSMutableParagraphStyle.alloc.init
36
+
37
+ paragrahStyle.setLineSpacing(options[:line_spacing]) if options[:line_spacing]
38
+ paragrahStyle.setAlignment(options[:text_alignment]) if options[:text_alignment]
39
+ paragrahStyle.setLineBreakMode(options[:line_break_mode]) if options[:line_break_mode]
40
+ attributes = {}
41
+ attributes[NSParagraphStyleAttributeName] = paragrahStyle
42
+ attributes[NSForegroundColorAttributeName] = options[:text_color]
43
+ attributes[NSFontAttributeName] = options[:font]
44
+
45
+ prepared_text = NSMutableAttributedString.alloc.initWithString(options[:text], attributes: attributes)
46
+ if underline_range = options[:underline]
47
+ # FIXME
48
+ # prepared_text = NSMutableAttributedString.alloc.initWithAttributedString(prepared_text)
49
+ # prepared_text.addAttributes({NSUnderlineStyleAttributeName => NSUnderlineStyleSingle}, range: underline_range)
50
+ end
51
+ prepared_text
52
+ end
53
+ end
54
+ end
@@ -21,12 +21,17 @@ module MotionPrime
21
21
  @options = options
22
22
  @screen = options[:screen]
23
23
  @section = options[:section]
24
+ @view_class = options[:view_class] || 'UIView'
24
25
  @name = options[:name]
25
26
  @block = options[:block]
26
- @view_class = options[:view_class] || 'UIView'
27
27
  @view_name = self.class_name_without_kvo.demodulize.underscore.gsub(/(_draw)?_element/, '')
28
28
  end
29
29
 
30
+ def dealloc
31
+ pp 'deallocating elemenet', self.name
32
+ super
33
+ end
34
+
30
35
  def render(options = {}, &block)
31
36
  run_callbacks :render do
32
37
  render!(&block)
@@ -46,6 +51,15 @@ module MotionPrime
46
51
  @computed_options
47
52
  end
48
53
 
54
+ def compute_options!
55
+ block_options = compute_block_options || {}
56
+ raw_options = self.options.except(:screen, :name, :block, :view_class).merge(block_options)
57
+ compute_style_options(raw_options)
58
+ raw_options = Styles.for(styles).merge(raw_options)
59
+ @computed_options = raw_options
60
+ normalize_options(@computed_options, section, %w[text placeholder font title_label padding padding_left padding_right min_width min_outer_width max_width max_outer_width width left right])
61
+ end
62
+
49
63
  def update_with_options(new_options = {})
50
64
  options.merge!(new_options)
51
65
  compute_options!
@@ -70,15 +84,6 @@ module MotionPrime
70
84
  end
71
85
 
72
86
  protected
73
- def compute_options!
74
- block_options = compute_block_options || {}
75
- raw_options = self.options.except(:screen, :name, :block, :view_class).merge(block_options)
76
- compute_style_options(raw_options)
77
- raw_options = Styles.for(styles).merge(raw_options)
78
-
79
- @computed_options = raw_options
80
- normalize_options(@computed_options, section, %w[text placeholder font title_label padding padding_left padding_right min_width min_outer_width max_width max_outer_width width left right])
81
- end
82
87
 
83
88
  # Compute options sent inside block, e.g.
84
89
  # element :button do
@@ -142,23 +147,23 @@ module MotionPrime
142
147
  # table element: categories_table_cell_icon, categories_table_title_icon
143
148
  @styles += build_styles_chain(base_styles[:specific], suffixes[:specific])
144
149
  end
145
- if section
150
+ if section && section.name.present? && name.present?
146
151
  # using for base sections
147
- @styles << [section.name, name].compact.join('_').to_sym
152
+ @styles << [section.name, name].join('_').to_sym
148
153
  end
149
154
  # custom style (from options or block options), using for TableViews as well
150
155
  custom_styles = style_sources.map do |source|
151
156
  normalize_object(source.delete(:styles), section)
152
157
  end.flatten
153
158
  @styles += custom_styles
154
- #puts @view_class.to_s + @styles.inspect, ''
159
+ # puts @view_class.to_s + @styles.inspect, ''
155
160
  end
156
161
 
157
162
  class << self
158
163
  def factory(type, options = {})
159
164
  element_class = class_factory("#{type}_element", true) || self
160
165
  view_class_name = camelize_factory("ui_#{type}")
161
-
166
+
162
167
  options.merge!(view_class: view_class_name)
163
168
  element_class.new(options)
164
169
  end
@@ -7,6 +7,19 @@ module MotionPrime
7
7
  include FrameCalculatorMixin
8
8
  include ElementContentPaddingMixin
9
9
 
10
+ def draw_options
11
+ options = computed_options
12
+ background_color = options[:background_color].try(:uicolor)
13
+ {
14
+ rect: CGRectMake(computed_left, computed_top, computed_outer_width, computed_outer_height),
15
+ background_color: background_color,
16
+ masks_to_bounds: options[:layer].try(:[], :masks_to_bounds) || options[:clips_to_bounds],
17
+ corner_radius: options[:layer].try(:[], :corner_radius).to_f,
18
+ border_width: options[:layer].try(:[], :border_width).to_f,
19
+ border_color: options[:layer].try(:[], :border_color).try(:uicolor) || background_color
20
+ }
21
+ end
22
+
10
23
  def render!; end
11
24
 
12
25
  def view
@@ -14,7 +27,7 @@ module MotionPrime
14
27
  end
15
28
 
16
29
  def computed_frame
17
- @computed_frame ||= calculate_frome_for(view.bounds, computed_options)
30
+ @computed_frame ||= calculate_frome_for(view.try(:bounds) || section.container_bounds, computed_options)
18
31
  end
19
32
 
20
33
  def default_padding_for(side)
@@ -61,8 +74,16 @@ module MotionPrime
61
74
  view.setNeedsDisplay
62
75
  end
63
76
 
77
+ def update_with_options(new_options = {})
78
+ options.merge!(new_options)
79
+ compute_options!
80
+ view.setNeedsDisplay
81
+ end
82
+
64
83
  private
65
84
  def reset_computed_values
85
+ @content_height = nil
86
+ @content_width = nil
66
87
  @computed_frame = nil
67
88
  end
68
89
 
@@ -1,35 +1,35 @@
1
1
  module MotionPrime
2
2
  module DrawBackgroundMixin
3
- def draw_background_in(draw_rect, options)
4
- bg_color = options[:background_color]
5
- border_radius = options[:layer].try(:[], :corner_radius)
6
- border_width = options[:layer].try(:[], :border_width).to_f
7
- border_color = options[:layer].try(:[], :border_color) || bg_color || :black
3
+ def draw_background_in_context(context = nil)
4
+ context ||= UIGraphicsGetCurrentContext()
5
+ options = draw_options
6
+ rect, background_color, border_width, border_color, corner_radius = options.slice(:rect, :background_color, :border_width, :border_color, :corner_radius).values
8
7
 
9
- if bg_color || border_width > 0
10
- inset = border_width > 0 ? (border_width - 1 )*0.5 : 0
11
- rect = CGRectInset(draw_rect, -inset, -inset)
12
- if border_radius
13
- bezierPath = UIBezierPath.bezierPathWithRoundedRect rect, cornerRadius: border_radius
14
- if border_width > 0
15
- bezierPath.lineWidth = border_width
16
- border_color.uicolor.setStroke
17
- bezierPath.stroke
18
- end
19
- if bg_color
20
- bg_color.uicolor.setFill
21
- bezierPath.fill
22
- end
23
- else
24
- context = UIGraphicsGetCurrentContext()
25
- if border_width > 0 && border_color
26
- CGContextSetLineWidth(context, border_width)
27
- CGContextSetStrokeColorWithColor(context, border_color.uicolor.cgcolor)
28
- CGContextStrokeRect(context, rect)
29
- end
30
- CGContextSetFillColorWithColor(context, bg_color.uicolor.cgcolor) if bg_color
31
- CGContextFillRect(context, rect) if bg_color
8
+ return unless background_color || border_width > 0
9
+
10
+ inset = border_width > 0 ? (border_width - 1 )*0.5 : 0
11
+ rect = CGRectInset(rect, -inset, -inset)
12
+ if corner_radius > 0
13
+ bezierPath = UIBezierPath.bezierPathWithRoundedRect rect, cornerRadius: corner_radius
14
+ UIGraphicsPushContext(context)
15
+ if border_width > 0
16
+ bezierPath.lineWidth = border_width
17
+ border_color.setStroke
18
+ bezierPath.stroke
19
+ end
20
+ if background_color
21
+ background_color.setFill
22
+ bezierPath.fill
23
+ end
24
+ UIGraphicsPopContext()
25
+ else
26
+ if border_width > 0 && border_color
27
+ CGContextSetLineWidth(context, border_width)
28
+ CGContextSetStrokeColorWithColor(context, border_color.uicolor.cgcolor)
29
+ CGContextStrokeRect(context, rect)
32
30
  end
31
+ CGContextSetFillColorWithColor(context, background_color.uicolor.cgcolor) if background_color
32
+ CGContextFillRect(context, rect) if background_color
33
33
  end
34
34
  end
35
35
  end
@@ -4,67 +4,86 @@ module MotionPrime
4
4
  include DrawBackgroundMixin
5
5
  attr_accessor :image_data
6
6
 
7
+ def draw_options
8
+ image = image_data || computed_options[:image]
9
+ image ||= computed_options[:default] if computed_options[:url]
10
+
11
+ # already initialized image or image from resources or default image
12
+ super.merge({image: image.try(:uiimage)})
13
+ end
14
+
7
15
  def draw_in(rect)
8
16
  return if computed_options[:hidden]
9
- options = computed_options
10
- image_rect = CGRectMake(
11
- computed_left,
12
- computed_top,
13
- computed_width,
14
- computed_height
15
- )
16
17
 
17
- image_rect = CGRectInset(image_rect, -0.5, -0.5)
18
- border_width = options[:layer].try(:[], :border_width).to_f
18
+ draw_background_in_context(UIGraphicsGetCurrentContext())
19
+ computed_options[:draw_in_rect] ? draw_in_context(UIGraphicsGetCurrentContext()) : draw_with_layer
20
+ load_image
21
+ end
19
22
 
20
- draw_background_in(image_rect, options)
23
+ def draw_in_context(context)
24
+ return if computed_options[:hidden]
21
25
 
22
- # draw already initialized image
23
- if image_data
24
- draw_with_layer(image_data, image_rect)
25
- # draw image from resources
26
- elsif computed_options[:image]
27
- self.image_data = computed_options[:image].uiimage
28
- draw_with_layer(image_data, image_rect)
29
- # show default image and download image from url
30
- elsif computed_options[:url]
31
- if computed_options[:default]
32
- self.image_data = computed_options[:default].uiimage
33
- draw_with_layer(image_data, image_rect)
34
- end
35
- manager = SDWebImageManager.sharedManager
36
- manager.downloadWithURL(computed_options[:url],
37
- options: 0,
38
- progress: lambda{ |r_size, e_size| },
39
- completed: lambda{ |image, error, type, finished|
40
- if image
41
- self.image_data = image
42
- if type == SDImageCacheTypeNone || type == SDImageCacheTypeDisk
43
- # if it's first call, we should redraw view, because it's async
44
- section.container_view.setNeedsDisplay
45
- else
46
- # if it's second call, we should just draw image
47
- draw_with_layer(image_data, image_rect)
48
- end
49
- end
50
- } )
26
+ draw_background_in_context(context)
27
+ options = draw_options
28
+ return unless image = options[:image]
29
+
30
+ border_width = options[:border_width]
31
+ inset = border_width > 0 ? (border_width - 1 ).abs*0.5 : 0
32
+ rect = CGRectInset(options[:rect], inset, inset)
33
+ radius = options[:corner_radius].to_f if options[:corner_radius] && options[:masks_to_bounds]
34
+
35
+ UIGraphicsPushContext(context)
36
+ if radius
37
+ CGContextBeginPath(context)
38
+ CGContextAddArc(context, rect.origin.x + rect.size.width/2, rect.origin.y + rect.size.height/2, radius, 0, 2*Math::PI, 0) # FIXME
39
+ CGContextClosePath(context)
40
+ CGContextSaveGState(context)
41
+ CGContextClip(context)
42
+ image.drawInRect(rect)
43
+ CGContextRestoreGState(context)
44
+ else
45
+ image.drawInRect(rect)
51
46
  end
47
+ UIGraphicsPopContext()
52
48
  end
53
49
 
54
- def draw_with_layer(image, rect)
50
+ def draw_with_layer
51
+ options = draw_options
52
+ return unless image = options[:image]
53
+ rect = options[:rect]
54
+ radius = options[:corner_radius].to_f if options[:corner_radius] && options[:masks_to_bounds]
55
+
55
56
  layer = CALayer.layer
56
57
  layer.contents = image.CGImage
57
58
  layer.frame = rect
58
59
  layer.bounds = rect
59
- if computed_options[:layer]
60
- layer.masksToBounds = computed_options[:layer][:masks_to_bounds] || computed_options[:clips_to_bounds]
61
- if radius = computed_options[:layer][:corner_radius]
62
- k = image.size.width / rect.size.width
63
- radius = radius * k
64
- layer.cornerRadius = radius
65
- end
60
+
61
+ layer.masksToBounds = options[:masks_to_bounds]
62
+ layer.cornerRadius = radius if radius
63
+
64
+ view.layer.addSublayer(layer)
65
+ end
66
+
67
+ def load_image
68
+ return if image_data || !computed_options[:url]
69
+ BW::Reactor.schedule do
70
+ manager = SDWebImageManager.sharedManager
71
+ manager.downloadWithURL(computed_options[:url],
72
+ options: 0,
73
+ progress: lambda{ |r_size, e_size| },
74
+ completed: lambda{ |image, error, type, finished|
75
+ break unless image && section
76
+ self.image_data = image
77
+
78
+ section.cached_draw_image = nil
79
+ if section.respond_to?(:cell_name)
80
+ section.pending_display!
81
+ else
82
+ self.view.performSelectorOnMainThread :setNeedsDisplay, withObject: nil, waitUntilDone: false
83
+ end
84
+ }
85
+ )
66
86
  end
67
- view.layer.addSublayer layer
68
87
  end
69
88
  end
70
89
  end