rmx 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +40 -0
- data/Rakefile +18 -0
- data/app/app_delegate.rb +5 -0
- data/lib/motion/RMXActionSheet.rb +14 -0
- data/lib/motion/RMXAutoLayoutLabel.rb +19 -0
- data/lib/motion/RMXAutoLayoutScrollView.rb +53 -0
- data/lib/motion/RMXCommonMethods.rb +27 -0
- data/lib/motion/RMXEventsFromProxy.rb +103 -0
- data/lib/motion/RMXExecutionBlock.rb +51 -0
- data/lib/motion/RMXKeyboardHelpers.rb +54 -0
- data/lib/motion/RMXLongTask.rb +133 -0
- data/lib/motion/RMXNavigationController.rb +133 -0
- data/lib/motion/RMXObjectExtensions.rb +10 -0
- data/lib/motion/RMXSegmentedController.rb +71 -0
- data/lib/motion/RMXSetAttributes.rb +34 -0
- data/lib/motion/RMXStrongToWeakHash.rb +46 -0
- data/lib/motion/RMXSynchronizedStrongToWeakHash.rb +40 -0
- data/lib/motion/RMXTableHandler.rb +212 -0
- data/lib/motion/RMXTableViewCell.rb +85 -0
- data/lib/motion/RMXTableViewCellInnerContentView.rb +16 -0
- data/lib/motion/RMXTableViewController.rb +65 -0
- data/lib/motion/RMXUnsafeUnretainedHolder.rb +30 -0
- data/lib/motion/RMXView.rb +84 -0
- data/lib/motion/RMXViewController.rb +65 -0
- data/lib/motion/RMXViewControllerPresentation.rb +127 -0
- data/lib/motion/RMXWeakHolder.rb +36 -0
- data/lib/motion/RMXWeakToStrongHash.rb +39 -0
- data/lib/motion/accessors.rb +29 -0
- data/lib/motion/base.rb +12 -0
- data/lib/motion/env.rb +9 -0
- data/lib/motion/events.rb +61 -0
- data/lib/motion/layout.rb +357 -0
- data/lib/motion/ui.rb +55 -0
- data/lib/motion/util.rb +155 -0
- data/lib/rmx/version.rb +3 -0
- data/lib/rmx.rb +50 -0
- data/resources/Default-568h@2x.png +0 -0
- data/rmx.gemspec +19 -0
- data/spec/main_spec.rb +240 -0
- metadata +86 -0
@@ -0,0 +1,133 @@
|
|
1
|
+
class RMXNavigationController < UINavigationController
|
2
|
+
|
3
|
+
include RMXCommonMethods
|
4
|
+
include RMXViewControllerPresentation
|
5
|
+
|
6
|
+
RMX.new(self).weak_attr_accessor :lastShownViewController
|
7
|
+
|
8
|
+
def animating?
|
9
|
+
if vc = viewControllers.last
|
10
|
+
vc != lastShownViewController
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def navigationController(navigationController, didShowViewController:view_controller, animated:animated)
|
15
|
+
self.lastShownViewController = view_controller
|
16
|
+
Dispatch::Queue.main.async do
|
17
|
+
unless animating?
|
18
|
+
navigationBar.userInteractionEnabled = true
|
19
|
+
RMX.new(self).trigger(:done_animating)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def pushViewController(view_controller, animated:animated)
|
25
|
+
unless animating?
|
26
|
+
super
|
27
|
+
else
|
28
|
+
navigationBar.userInteractionEnabled = false
|
29
|
+
p "DELAYED pushViewController:animated:", view_controller, animated
|
30
|
+
RMX.new(self).once(:done_animating) do
|
31
|
+
p "RESUMED pushViewController:animated:", view_controller, animated
|
32
|
+
pushViewController(view_controller, animated:animated)
|
33
|
+
end
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def popViewControllerAnimated(animated)
|
39
|
+
unless animating?
|
40
|
+
super
|
41
|
+
else
|
42
|
+
navigationBar.userInteractionEnabled = false
|
43
|
+
p "DELAYED popViewControllerAnimated:", animated
|
44
|
+
RMX.new(self).once(:done_animating) do
|
45
|
+
p "RESUMED popViewControllerAnimated:", animated
|
46
|
+
popViewControllerAnimated(animated)
|
47
|
+
end
|
48
|
+
nil
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def popToRootViewControllerAnimated(animated)
|
53
|
+
unless animating?
|
54
|
+
super
|
55
|
+
else
|
56
|
+
navigationBar.userInteractionEnabled = false
|
57
|
+
p "DELAYED popToRootViewControllerAnimated:", animated
|
58
|
+
RMX.new(self).once(:done_animating) do
|
59
|
+
p "RESUMED popToRootViewControllerAnimated:", animated
|
60
|
+
popToRootViewControllerAnimated(animated)
|
61
|
+
end
|
62
|
+
nil
|
63
|
+
end
|
64
|
+
end
|
65
|
+
def popToViewController(view_controller, animated:animated)
|
66
|
+
unless animating?
|
67
|
+
super
|
68
|
+
else
|
69
|
+
navigationBar.userInteractionEnabled = false
|
70
|
+
p "DELAYED popToViewController:animated:", view_controller, animated
|
71
|
+
RMX.new(self).once(:done_animating) do
|
72
|
+
p "RESUMED popToViewController:animated:", view_controller, animated
|
73
|
+
popToViewController(view_controller, animated:animated)
|
74
|
+
end
|
75
|
+
nil
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def viewDidLoad
|
80
|
+
s = super
|
81
|
+
s
|
82
|
+
end
|
83
|
+
|
84
|
+
def viewWillAppear(animated)
|
85
|
+
s = super
|
86
|
+
rmx_viewWillAppear(animated)
|
87
|
+
s
|
88
|
+
end
|
89
|
+
|
90
|
+
def viewDidAppear(animated)
|
91
|
+
s = super
|
92
|
+
rmx_viewDidAppear(animated)
|
93
|
+
s
|
94
|
+
end
|
95
|
+
|
96
|
+
def viewWillDisappear(animated)
|
97
|
+
s = super
|
98
|
+
resignApplicationFirstResponder
|
99
|
+
rmx_viewWillDisappear(animated)
|
100
|
+
s
|
101
|
+
end
|
102
|
+
|
103
|
+
def viewDidDisappear(animated)
|
104
|
+
s = super
|
105
|
+
rmx_viewDidDisappear(animated)
|
106
|
+
s
|
107
|
+
end
|
108
|
+
|
109
|
+
def resignApplicationFirstResponder
|
110
|
+
windows = [] + UIApplication.sharedApplication.windows
|
111
|
+
while window = windows.pop
|
112
|
+
window.endEditing(true)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def didReceiveMemoryWarning
|
117
|
+
p "didReceiveMemoryWarning"
|
118
|
+
super
|
119
|
+
end
|
120
|
+
|
121
|
+
def rmx_dealloc
|
122
|
+
NSNotificationCenter.defaultCenter.removeObserver(self)
|
123
|
+
super
|
124
|
+
end
|
125
|
+
|
126
|
+
def self.create(rootViewController)
|
127
|
+
v = alloc.initWithNavigationBarClass(UINavigationBar, toolbarClass:nil)
|
128
|
+
v.delegate = v
|
129
|
+
v.pushViewController(rootViewController, animated: false) if rootViewController
|
130
|
+
v
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
class RMXSegmentedController < RMXViewController
|
2
|
+
|
3
|
+
def prepare
|
4
|
+
@controller_indexes = []
|
5
|
+
@control = UISegmentedControl.new
|
6
|
+
@control.addTarget(self, action:'control_change:', forControlEvents:UIControlEventValueChanged)
|
7
|
+
end
|
8
|
+
|
9
|
+
def loaded
|
10
|
+
navigationItem.titleView = @control
|
11
|
+
self.selectedIndex = 0
|
12
|
+
end
|
13
|
+
|
14
|
+
def segments=(segments)
|
15
|
+
@controller_indexes.clear
|
16
|
+
@control.removeAllSegments
|
17
|
+
if segments
|
18
|
+
segments.each_with_index do |segment, i|
|
19
|
+
if segment[:title]
|
20
|
+
@control.insertSegmentWithTitle(segment[:title], atIndex:i, animated:false)
|
21
|
+
elsif segment[:image]
|
22
|
+
@control.insertSegmentWithImage(segment[:image], atIndex:i, animated:false)
|
23
|
+
end
|
24
|
+
@controller_indexes[i] = segment[:controller]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
@control.sizeToFit
|
28
|
+
end
|
29
|
+
|
30
|
+
def control_change(sender)
|
31
|
+
self.selectedIndex = sender.selectedSegmentIndex
|
32
|
+
end
|
33
|
+
|
34
|
+
def selectedIndex=(i)
|
35
|
+
cleanup_active
|
36
|
+
@control.selectedSegmentIndex = @control.numberOfSegments > i ? i : UISegmentedControlNoSegment
|
37
|
+
@active_controller = @controller_indexes[i]
|
38
|
+
if @active_controller
|
39
|
+
addChildViewController(@active_controller)
|
40
|
+
RMX::Layout.new do |layout|
|
41
|
+
layout.view = view
|
42
|
+
layout.subviews = {
|
43
|
+
"content" => @active_controller.view
|
44
|
+
}
|
45
|
+
layout.eqs %Q{
|
46
|
+
content.left == 0
|
47
|
+
content.right == 0
|
48
|
+
content.top == 0
|
49
|
+
content.bottom == 0
|
50
|
+
}
|
51
|
+
end
|
52
|
+
@active_controller.didMoveToParentViewController(self)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def cleanup_active
|
57
|
+
if @active_controller
|
58
|
+
@active_controller.willMoveToParentViewController(nil)
|
59
|
+
@active_controller.view.removeFromSuperview
|
60
|
+
@active_controller.removeFromParentViewController
|
61
|
+
@active_controller = nil
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def rmx_dealloc
|
66
|
+
cleanup_active
|
67
|
+
@controller_indexes = nil
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module RMXSetAttributes
|
2
|
+
|
3
|
+
def self.included(klass)
|
4
|
+
klass.send(:include, InstanceMethods)
|
5
|
+
klass.send(:extend, ClassMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
module InstanceMethods
|
9
|
+
|
10
|
+
def after_attributes_set
|
11
|
+
end
|
12
|
+
|
13
|
+
def attributes=(attrs={})
|
14
|
+
keys = [] + attrs.keys
|
15
|
+
while key = keys.pop
|
16
|
+
value = attrs[key]
|
17
|
+
self.send("#{key}=", value)
|
18
|
+
end
|
19
|
+
after_attributes_set
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
module ClassMethods
|
25
|
+
|
26
|
+
def create(opts={})
|
27
|
+
x = new
|
28
|
+
x.attributes = opts
|
29
|
+
x
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
class RMXStrongToWeakHash < Hash
|
2
|
+
|
3
|
+
def [](key)
|
4
|
+
if weak = super
|
5
|
+
if val = weak.value
|
6
|
+
val
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def []=(key, value)
|
12
|
+
super(key, value.nil? ? nil : RMXWeakHolder.new(value))
|
13
|
+
value
|
14
|
+
end
|
15
|
+
|
16
|
+
def delete(key)
|
17
|
+
if val = super
|
18
|
+
val.value
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def keys
|
23
|
+
out = []
|
24
|
+
_keys = [] + super
|
25
|
+
while _keys.size > 0
|
26
|
+
key = _keys.shift
|
27
|
+
if val = self[key]
|
28
|
+
out << key
|
29
|
+
end
|
30
|
+
end
|
31
|
+
out
|
32
|
+
end
|
33
|
+
|
34
|
+
def values
|
35
|
+
out = []
|
36
|
+
values = [] + super
|
37
|
+
while values.size > 0
|
38
|
+
value = values.shift
|
39
|
+
if val = value.value
|
40
|
+
out << val
|
41
|
+
end
|
42
|
+
end
|
43
|
+
out
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class RMXSynchronizedStrongToWeakHash < RMXStrongToWeakHash
|
2
|
+
|
3
|
+
def initialize
|
4
|
+
super
|
5
|
+
@queue = Dispatch::Queue.new("#{NSBundle.mainBundle.bundleIdentifier}.rmx.IdentityMap.queue.#{object_id}")
|
6
|
+
end
|
7
|
+
|
8
|
+
def [](key)
|
9
|
+
res = nil
|
10
|
+
@queue.sync do
|
11
|
+
res = super
|
12
|
+
end
|
13
|
+
res
|
14
|
+
end
|
15
|
+
|
16
|
+
def []=(key, value)
|
17
|
+
res = nil
|
18
|
+
@queue.sync do
|
19
|
+
res = super
|
20
|
+
end
|
21
|
+
res
|
22
|
+
end
|
23
|
+
|
24
|
+
def delete(key)
|
25
|
+
res = nil
|
26
|
+
@queue.sync do
|
27
|
+
res = super
|
28
|
+
end
|
29
|
+
res
|
30
|
+
end
|
31
|
+
|
32
|
+
def values
|
33
|
+
res = nil
|
34
|
+
@queue.sync do
|
35
|
+
res = super
|
36
|
+
end
|
37
|
+
res
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,212 @@
|
|
1
|
+
class RMXTableHandler
|
2
|
+
|
3
|
+
include RMXCommonMethods
|
4
|
+
|
5
|
+
RMX.new(self).weak_attr_accessor :tableView, :delegate
|
6
|
+
|
7
|
+
attr_accessor :registered_reuse_identifiers, :sections
|
8
|
+
|
9
|
+
def self.forTable(tableView)
|
10
|
+
x = new
|
11
|
+
x.tableView = tableView
|
12
|
+
tableView.dataSource = x
|
13
|
+
tableView.delegate = x
|
14
|
+
x
|
15
|
+
end
|
16
|
+
|
17
|
+
def rmx_dealloc
|
18
|
+
if tv = tableView
|
19
|
+
tv.dataSource = nil
|
20
|
+
tv.delegate = nil
|
21
|
+
end
|
22
|
+
RMX.new(self).nil_instance_variables!
|
23
|
+
super
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize
|
27
|
+
@sections = []
|
28
|
+
@heights = {}
|
29
|
+
@registered_reuse_identifiers = {}
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
def animateUpdates
|
34
|
+
if @isAnimatingUpdates
|
35
|
+
@animateUpdatesAgain = true
|
36
|
+
return
|
37
|
+
end
|
38
|
+
@isAnimatingUpdates = true
|
39
|
+
CATransaction.begin
|
40
|
+
CATransaction.setCompletionBlock(lambda do
|
41
|
+
p "animation has finished"
|
42
|
+
@isAnimatingUpdates = false
|
43
|
+
if @animateUpdatesAgain
|
44
|
+
p "animate again!"
|
45
|
+
@animateUpdatesAgain = false
|
46
|
+
animateUpdates
|
47
|
+
end
|
48
|
+
end)
|
49
|
+
tableView.beginUpdates
|
50
|
+
tableView.endUpdates
|
51
|
+
CATransaction.commit
|
52
|
+
end
|
53
|
+
|
54
|
+
def reloadData
|
55
|
+
if tv = tableView
|
56
|
+
tv.reloadData
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def set_size_for_data(data, reuseIdentifier:reuseIdentifier)
|
61
|
+
reuseIdentifier = reuseIdentifier.to_s
|
62
|
+
sizerCell = registered_reuse_identifiers[reuseIdentifier]
|
63
|
+
sizerCell.data = data
|
64
|
+
height = sizerCell.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
|
65
|
+
updateHeight(height, data:data, reuseIdentifier:reuseIdentifier)
|
66
|
+
end
|
67
|
+
|
68
|
+
def registerClass(klass, forCellReuseIdentifier:reuseIdentifier)
|
69
|
+
reuseIdentifier = reuseIdentifier.to_s
|
70
|
+
registered_reuse_identifiers[reuseIdentifier] = klass.new
|
71
|
+
tableView.registerClass(klass, forCellReuseIdentifier:reuseIdentifier)
|
72
|
+
end
|
73
|
+
|
74
|
+
def tableView(tableView, cellForRowAtIndexPath:indexPath)
|
75
|
+
RMX.assert_main_thread!
|
76
|
+
context = {
|
77
|
+
:tableHandler => self,
|
78
|
+
:tableView => tableView,
|
79
|
+
:indexPath => indexPath,
|
80
|
+
:data => delegate.tableHandler(self, dataForSectionName:@sections[indexPath.section])[indexPath.row]
|
81
|
+
}
|
82
|
+
res = delegate.tableHandler(self, cellOptsForContext:context)
|
83
|
+
if res.is_a?(Hash)
|
84
|
+
context.update(res)
|
85
|
+
unless res[:reuseIdentifier]
|
86
|
+
raise ":reuseIdentifier is required"
|
87
|
+
end
|
88
|
+
reuseIdentifier = res[:reuseIdentifier].to_s
|
89
|
+
registered_reuse_identifiers[reuseIdentifier] || registerClass(RMXTableViewCell, forCellReuseIdentifier:reuseIdentifier)
|
90
|
+
res = tableView.dequeueReusableCellWithIdentifier(reuseIdentifier, forIndexPath:indexPath)
|
91
|
+
res.context = context
|
92
|
+
end
|
93
|
+
# p "cellForRowAtIndexPath", res, context
|
94
|
+
res
|
95
|
+
end
|
96
|
+
|
97
|
+
def tableView(tableView, heightForRowAtIndexPath:indexPath)
|
98
|
+
RMX.assert_main_thread!
|
99
|
+
context = {
|
100
|
+
:tableHandler => self,
|
101
|
+
:tableView => tableView,
|
102
|
+
:indexPath => indexPath,
|
103
|
+
:data => delegate.tableHandler(self, dataForSectionName:@sections[indexPath.section])[indexPath.row]
|
104
|
+
}
|
105
|
+
res = if @respondsToHeightForContext || delegate.respondsToSelector('tableHandler:heightForContext:')
|
106
|
+
@respondsToHeightForContext = true
|
107
|
+
delegate.tableHandler(self, heightForContext:context)
|
108
|
+
else
|
109
|
+
delegate.tableHandler(self, cellOptsForContext:context)
|
110
|
+
end
|
111
|
+
if res.is_a?(Hash)
|
112
|
+
context.update(res)
|
113
|
+
unless res[:reuseIdentifier]
|
114
|
+
raise ":reuseIdentifier is required"
|
115
|
+
end
|
116
|
+
reuseIdentifier = res[:reuseIdentifier].to_s
|
117
|
+
height = nil
|
118
|
+
if res[:data]
|
119
|
+
if heights = @heights[reuseIdentifier]
|
120
|
+
height = heights[res[:data]]
|
121
|
+
end
|
122
|
+
end
|
123
|
+
unless height
|
124
|
+
# p "using estimated"
|
125
|
+
height = res[:estimated]
|
126
|
+
# else
|
127
|
+
# p "using real"
|
128
|
+
end
|
129
|
+
res = height
|
130
|
+
end
|
131
|
+
# p "heightForRowAtIndexPath", indexPath, res
|
132
|
+
res
|
133
|
+
end
|
134
|
+
|
135
|
+
def tableView(tableView, estimatedHeightForRowAtIndexPath:indexPath)
|
136
|
+
tableView(tableView, heightForRowAtIndexPath:indexPath)
|
137
|
+
end
|
138
|
+
|
139
|
+
def tableView(tableView, viewForHeaderInSection:section)
|
140
|
+
RMX.assert_main_thread!
|
141
|
+
if @respondsToHeaderForContext || delegate.respondsToSelector('tableHandler:headerForContext:')
|
142
|
+
@respondsToHeaderForContext = true
|
143
|
+
context = {
|
144
|
+
:tableHandler => self,
|
145
|
+
:tableView => tableView,
|
146
|
+
:section => section
|
147
|
+
}
|
148
|
+
res = delegate.tableHandler(self, headerForContext:context)
|
149
|
+
# p "viewForHeaderInSection", section, res
|
150
|
+
res
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def tableView(tableView, heightForHeaderInSection:section)
|
155
|
+
RMX.assert_main_thread!
|
156
|
+
if @respondsToHeaderHeightForContext || delegate.respondsToSelector('tableHandler:headerHeightForContext:')
|
157
|
+
@respondsToHeaderHeightForContext = true
|
158
|
+
context = {
|
159
|
+
:tableHandler => self,
|
160
|
+
:tableView => tableView,
|
161
|
+
:section => section
|
162
|
+
}
|
163
|
+
res = delegate.tableHandler(self, headerHeightForContext:context)
|
164
|
+
# p "heightForHeaderInSection", section, res
|
165
|
+
res
|
166
|
+
else
|
167
|
+
0
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def tableView(tableView, numberOfRowsInSection: section)
|
172
|
+
RMX.assert_main_thread!
|
173
|
+
res = delegate.tableHandler(self, dataForSectionName:@sections[section]).size
|
174
|
+
# p "numberOfRowsInSection", res
|
175
|
+
res
|
176
|
+
end
|
177
|
+
|
178
|
+
def numberOfSectionsInTableView(tableView)
|
179
|
+
RMX.assert_main_thread!
|
180
|
+
res = @sections.size
|
181
|
+
# p "numberOfSectionsInTableView", res
|
182
|
+
res
|
183
|
+
end
|
184
|
+
|
185
|
+
def tableView(tableView, didSelectRowAtIndexPath:indexPath)
|
186
|
+
RMX.assert_main_thread!
|
187
|
+
if @respondsToClickForContext || delegate.respondsToSelector('tableHandler:clickForContext:')
|
188
|
+
@respondsToClickForContext = true
|
189
|
+
context = {
|
190
|
+
:tableHandler => self,
|
191
|
+
:tableView => tableView,
|
192
|
+
:indexPath => indexPath,
|
193
|
+
:data => delegate.tableHandler(self, dataForSectionName:@sections[indexPath.section])[indexPath.row]
|
194
|
+
}
|
195
|
+
delegate.tableHandler(self, clickForContext:context)
|
196
|
+
tableView.deselectRowAtIndexPath(indexPath, animated:true)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def updateHeight(height, data:data, reuseIdentifier:reuseIdentifier)
|
201
|
+
reuseIdentifier = reuseIdentifier.to_s
|
202
|
+
@heights[reuseIdentifier] ||= {}
|
203
|
+
heights = @heights[reuseIdentifier]
|
204
|
+
current_height = heights[data]
|
205
|
+
if current_height != height
|
206
|
+
heights[data] = height
|
207
|
+
return true
|
208
|
+
end
|
209
|
+
false
|
210
|
+
end
|
211
|
+
|
212
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
class RMXTableViewCell < UITableViewCell
|
2
|
+
|
3
|
+
include RMXCommonMethods
|
4
|
+
|
5
|
+
RMX.new(self).weak_attr_accessor :tableView
|
6
|
+
RMX.new(self).weak_attr_accessor :tableHandler
|
7
|
+
attr_accessor :indexPath, :innerContentView
|
8
|
+
|
9
|
+
def initWithStyle(style, reuseIdentifier:reuseIdentifier)
|
10
|
+
reuseIdentifier = reuseIdentifier.to_s
|
11
|
+
s = super(style, reuseIdentifier)
|
12
|
+
@innerContentView = RMXTableViewCellInnerContentView.new
|
13
|
+
@innerContentView.cell = self
|
14
|
+
RMX::Layout.new do |layout|
|
15
|
+
layout.view = contentView
|
16
|
+
layout.subviews = {
|
17
|
+
"innerContentView" => @innerContentView
|
18
|
+
}
|
19
|
+
layout.eqs %Q{
|
20
|
+
innerContentView.top == 0
|
21
|
+
innerContentView.left == 0
|
22
|
+
innerContentView.right == 0
|
23
|
+
innerContentView.bottom == 0 @ med
|
24
|
+
}
|
25
|
+
end
|
26
|
+
setup
|
27
|
+
s
|
28
|
+
end
|
29
|
+
|
30
|
+
def context=(context)
|
31
|
+
self.tableHandler = context[:tableHandler]
|
32
|
+
self.tableView = context[:tableView]
|
33
|
+
self.indexPath = context[:indexPath]
|
34
|
+
self.data = context[:data]
|
35
|
+
self.view = context[:view]
|
36
|
+
if context[:transform] && transform != context[:transform]
|
37
|
+
self.transform = context[:transform]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def setup
|
42
|
+
end
|
43
|
+
|
44
|
+
def data
|
45
|
+
@data
|
46
|
+
end
|
47
|
+
|
48
|
+
def data=(data)
|
49
|
+
@data = data
|
50
|
+
end
|
51
|
+
|
52
|
+
def view
|
53
|
+
@view
|
54
|
+
end
|
55
|
+
|
56
|
+
def view=(view)
|
57
|
+
@view.removeFromSuperview if @view
|
58
|
+
if @view = view
|
59
|
+
RMX::Layout.new do |layout|
|
60
|
+
layout.view = innerContentView
|
61
|
+
layout.subviews = {
|
62
|
+
"tile" => view
|
63
|
+
}
|
64
|
+
layout.eqs %Q{
|
65
|
+
tile.top == 0
|
66
|
+
tile.left == 0
|
67
|
+
tile.right == 0
|
68
|
+
tile.bottom == 0 @ 500
|
69
|
+
}
|
70
|
+
end
|
71
|
+
end
|
72
|
+
view
|
73
|
+
end
|
74
|
+
|
75
|
+
def updateHeight!
|
76
|
+
if (d = data) && (h = tableHandler)
|
77
|
+
height = contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
|
78
|
+
# p "height", height
|
79
|
+
if h.updateHeight(height, data:d, reuseIdentifier:reuseIdentifier)
|
80
|
+
h.reloadData
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class RMXTableViewCellInnerContentView < RMXView
|
2
|
+
RMX.new(self).weak_attr_accessor :cell
|
3
|
+
attr_accessor :autoUpdateHeight
|
4
|
+
|
5
|
+
def layoutSubviews
|
6
|
+
s = super
|
7
|
+
updateHeight! if @autoUpdateHeight
|
8
|
+
s
|
9
|
+
end
|
10
|
+
|
11
|
+
def updateHeight!
|
12
|
+
if c = cell
|
13
|
+
c.updateHeight!
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
class RMXTableViewController < UITableViewController
|
2
|
+
|
3
|
+
include RMXCommonMethods
|
4
|
+
include RMXViewControllerPresentation
|
5
|
+
include RMXKeyboardHelpers
|
6
|
+
include RMXSetAttributes
|
7
|
+
|
8
|
+
def prepare
|
9
|
+
end
|
10
|
+
|
11
|
+
def loaded
|
12
|
+
end
|
13
|
+
|
14
|
+
def init
|
15
|
+
s = super
|
16
|
+
NSNotificationCenter.defaultCenter.addObserver(self, selector:'refresh', name:UIApplicationWillEnterForegroundNotification, object:nil)
|
17
|
+
listenForKeyboardChanged
|
18
|
+
prepare
|
19
|
+
s
|
20
|
+
end
|
21
|
+
|
22
|
+
def refresh
|
23
|
+
end
|
24
|
+
|
25
|
+
def viewDidLoad
|
26
|
+
s = super
|
27
|
+
loaded
|
28
|
+
s
|
29
|
+
end
|
30
|
+
|
31
|
+
def viewWillAppear(animated)
|
32
|
+
s = super
|
33
|
+
rmx_viewWillAppear(animated)
|
34
|
+
s
|
35
|
+
end
|
36
|
+
|
37
|
+
def viewDidAppear(animated)
|
38
|
+
s = super
|
39
|
+
rmx_viewDidAppear(animated)
|
40
|
+
s
|
41
|
+
end
|
42
|
+
|
43
|
+
def viewWillDisappear(animated)
|
44
|
+
s = super
|
45
|
+
rmx_viewWillDisappear(animated)
|
46
|
+
s
|
47
|
+
end
|
48
|
+
|
49
|
+
def viewDidDisappear(animated)
|
50
|
+
s = super
|
51
|
+
rmx_viewDidDisappear(animated)
|
52
|
+
s
|
53
|
+
end
|
54
|
+
|
55
|
+
def didReceiveMemoryWarning
|
56
|
+
p "didReceiveMemoryWarning"
|
57
|
+
super
|
58
|
+
end
|
59
|
+
|
60
|
+
def rmx_dealloc
|
61
|
+
NSNotificationCenter.defaultCenter.removeObserver(self)
|
62
|
+
super
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|