rm-extensions 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2ba4ba13ce05f6391b658a6d6968fd368d6eb66e
4
- data.tar.gz: 9140c139f8dc4c75d01183e46019df8ebac3a7c2
3
+ metadata.gz: 5d64ca280c2914d4e0e8ebda0af7b8900c4a71d0
4
+ data.tar.gz: 422760a452010841d394d296a59090c5967b43cd
5
5
  SHA512:
6
- metadata.gz: 4ba45a55bbee4a13e6d0d72326208e4c704377ad24b28c6e04569e857cfeb74e869e9d846e9744367432e34068f8808dd502326f79b9cf242dfcebdb541b7c6c
7
- data.tar.gz: 03222f43b0510a630fd09b33f30bc59815c06ad6d54e41384f76880d0f645bb449ff297ee689d01988235ff66d4a8be31df1385d60b174b6c7222be4c18d7c4e
6
+ metadata.gz: 613afb58ed64e974e51cdfc117e8627ecc381084c2d1cf6e571b2d0df6a95ba071fab76efeda59cf9eb0e6a203a3d9cce1908a5e3cdf05be8b9179e8c947c4dd
7
+ data.tar.gz: 41375da6369ebe8921c5f47d2576ea774cc353b8701774e092ffaf7df6948e6b65b87bf203f10c2a055603e324c93b8ee4689205f76f5597ee267ee38a45f86d
data/Gemfile CHANGED
@@ -1,4 +1,7 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- # Specify your gem's dependencies in rm-extensions.gemspec
3
+ group :test, :development do
4
+ gem 'rake'
5
+ end
6
+
4
7
  gemspec
data/README.md CHANGED
@@ -1,7 +1,204 @@
1
1
  RMExtensions
2
2
  -----------------
3
3
 
4
- #### Extensions and helpers for dealing with various areas of rubymotion.
4
+ #### Extensions and helpers for dealing with various areas of rubymotion and iOS.
5
+
6
+ ## Equation-style AutoLayout Constraints
7
+
8
+ AutoLayout is a great way to lay out views, but writing constraints manually is
9
+ confusing and verbose.
10
+
11
+ Using Apple's "Visual Format Language" ASCII-inspired
12
+ strings can improve things, but it has drawbacks: **1)** It returns an array
13
+ of constraints. This means if you plan on altering one of them later, or removing
14
+ one in particular, you would have to loop through all of the constraints, testing
15
+ each one to see if its the one you want. **2)** The `options` argument adds additional
16
+ constraints. For example, if you specify NSLayoutAttributeCenterY to a horizontal string,
17
+ an additional constraint will be added for each view to set their centerY's equal to each
18
+ other. This compounds problem #1. The chances you will get an error that the layout system
19
+ cannot satisfy your constraints is probably because of these "extra" constraints. **3)**
20
+ It can't handle complex constraints, so you end up needing to supplement it with
21
+ verbose low-level constraint creation anyway.
22
+
23
+ Apple makes note of how constraints can be thought of like a linear equation:
24
+
25
+ http://developer.apple.com/library/ios/documentation/AppKit/Reference/NSLayoutConstraint_Class/NSLayoutConstraint/NSLayoutConstraint.html
26
+
27
+ **Remember the formula:**
28
+
29
+ ```ruby
30
+ view1.attr1 == view2.attr2 * multiplier + constant @ priority
31
+ ```
32
+
33
+ **We can actually use this super-simple formula to write ALL of our constraints, simple OR complex!**
34
+
35
+ Once you get the hang of the formula and visualization of how the geometry works, it becomes easy to create complex layouts with little
36
+ effort. And, in my opinion, its only slightly more verbose than the visual format language, but much clearer, and you only end up
37
+ with the exact constraints you want.
38
+
39
+ Available values for `attr1` and `attr2` are:
40
+
41
+ - left
42
+ - right
43
+ - top
44
+ - bottom
45
+ - leading
46
+ - trailing
47
+ - width
48
+ - height
49
+ - centerX
50
+ - centerY
51
+ - baseline
52
+
53
+ Available `relation` values are:
54
+
55
+ - ==
56
+ - <=
57
+ - >=
58
+
59
+ Available `priority` values are:
60
+
61
+ - required (1000 is the default)
62
+ - high (750)
63
+ - low (250)
64
+ - fit (50)
65
+ - or, you can use your own value between 1-1000
66
+
67
+
68
+ ### Examples
69
+
70
+ Here is a real example. The Layout instance is created just like the motion-layout gem. `layout.view` sets the view
71
+ that will act as the 'superview' to the views set in `layout.subviews`. Thats where the similarities end with
72
+ motion-layout. With RMExtensions::Layout, there are two methods: `eq` and `eqs`, short for equation and equations.
73
+
74
+ - `layout.eq` takes one string, and returns *one constraint*
75
+ - `layout.eqs` takes one string, assumes multiple constraints are separated by newlines, and returns an *array of constraints*
76
+
77
+ ```ruby
78
+ RMExtensions::Layout.new do |layout|
79
+ layout.view view
80
+ layout.subviews({
81
+ "calendar" => calendarView,
82
+ "table" => tableView,
83
+ "shadow" => line
84
+ })
85
+
86
+ layout.eqs %Q{
87
+ calendar.left == 0
88
+ calendar.right == 0
89
+ table.left == 7
90
+ table.right == -7
91
+ shadow.left == 0
92
+ shadow.right == 0
93
+
94
+ calendar.top == 0
95
+ table.top == calendar.bottom
96
+ table.bottom == 0
97
+ shadow.top == table.top
98
+ }
99
+
100
+ @calendar_height_constraint = layout.eq "calendar.height == 0"
101
+ end
102
+ ```
103
+
104
+ Above, **calendar.left == 0** is short for **calendar.left == view.left * 1.0 + 0 @ 1000**. If no view2 is given, the superview ('view') is assumed.
105
+ If no multiplier is given, 1.0 is assumed. If no constant is given, 0 is assumed. If no priority is given, "required" (1000) is assumed.
106
+ The last constraint is created separately and stored in @calendar_height_constraint, because I want to be able to change the calendar's height
107
+ any time I want.
108
+
109
+ Here is another example:
110
+
111
+ ```ruby
112
+ RMExtensions::Layout.new do |layout|
113
+ layout.view self
114
+ layout.subviews({
115
+ "timeLabel" => @timeLabel,
116
+ "titleLabel" => @titleLabel,
117
+ "trackingImage" => @trackingImage,
118
+ "inOutStatusInImage" => @inOutStatusInImage,
119
+ "inOutStatusOutImage" => @inOutStatusOutImage,
120
+ "plannerImage" => @plannerImage,
121
+ "shareButton" => @shareButton,
122
+ "cancelledLabel" => @cancelledLabel,
123
+ "unreadImage" => @unreadImage
124
+ })
125
+
126
+ layout.eqs %Q{
127
+ unreadImage.left == 6
128
+ unreadImage.top == 6
129
+ plannerImage.left == 14
130
+ plannerImage.centerY == 0
131
+ plannerImage.width == 30
132
+ plannerImage.height == 30
133
+ trackingImage.left == timeLabel.right + 5
134
+ inOutStatusOutImage.left == trackingImage.right + 5
135
+ inOutStatusInImage.left == inOutStatusOutImage.right + 5
136
+ timeLabel.left == plannerImage.right + 5
137
+ timeLabel.baseline == plannerImage.bottom + 1
138
+ trackingImage.centerY == timeLabel.centerY
139
+ inOutStatusOutImage.centerY == timeLabel.centerY
140
+ inOutStatusInImage.centerY == timeLabel.centerY
141
+ titleLabel.left == cancelledLabel.right
142
+ cancelledLabel.left == plannerImage.right + 5
143
+ titleLabel.top == plannerImage.top - 4
144
+ cancelledLabel.centerY == titleLabel.centerY
145
+ shareButton.right == -10
146
+ shareButton.centerY == 0
147
+ titleLabel.resistH == low
148
+ shareButton.left >= titleLabel.right + 5
149
+ timeLabel.resistH == low
150
+ shareButton.left >= inOutStatusInImage.right + 5
151
+ }
152
+
153
+ end
154
+ ```
155
+
156
+ Keep in mind none of these lines are using the multiplier, and thats OK. I've only needed it on one constraint in my entire app so far,
157
+ so don't think its odd if you can't find a use for it.
158
+
159
+ There are two special cases at the moment. **titleLabel.resistH == low** is not a "real" constraint. Its a shortcut to
160
+ `setContentCompressionResistancePriority`, and since its common when dealing with autolayout, its nice to include it
161
+ in our layout code. The same is done for `setContentHuggingPriority`. The full list of "special cases" at the moment:
162
+
163
+ - view1.resistH == priority
164
+ - view1.resistV == priority
165
+ - view1.hugH == priority
166
+ - view1.hugV == priority
167
+
168
+ "priority" can be one of the values listed earlier, or your own number between 1-1000.
169
+
170
+ ### Debugging constraints
171
+
172
+ - You can include a **?** on any line, and debug output will be printed when that constraint is built:
173
+
174
+ ```ruby
175
+ layout.eqs %Q{
176
+ label.left == photo.right + 5 ?
177
+ }
178
+ ```
179
+
180
+ - Since layout.eqs allows you to write many constraints in one string, and sometimes its nice to
181
+ keep comments next to constraints, **comments are allowed**:
182
+
183
+ ```ruby
184
+ layout.eqs %Q{
185
+ commentsCount.width == likesCount.width @ low # the widths of the labels prefer to be the same
186
+ }
187
+ ```
188
+
189
+ ### Things to remember
190
+
191
+ - Remember you usually want negative constants for right and bottom. For example: label.right == -10 means "label's right should be 10 away from the right side of the superview". But if you accidentally said label.right == 10, you would have created "label's right should be 10 PAST the right side of the superview". It may require you to adjust your thinking.
192
+
193
+ - The formula is just shorthand for `constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:`. You should **really** read up on constraints and
194
+ understand this method, to fully understand the power and simplicity the shorthand formula gives you.
195
+
196
+
197
+
198
+
199
+
200
+
201
+
5
202
 
6
203
  ## Observation/KVO, Events
7
204
 
data/Rakefile CHANGED
@@ -1 +1,16 @@
1
1
  require "bundler/gem_tasks"
2
+ $:.unshift('/Library/RubyMotion/lib')
3
+ if ENV.fetch('platform', 'ios') == 'ios'
4
+ require 'motion/project/template/ios'
5
+ elsif ENV['platform'] == 'osx'
6
+ require 'motion/project/template/osx'
7
+ else
8
+ raise "Unsupported platform #{ENV['platform']}"
9
+ end
10
+ require 'bundler'
11
+ Bundler.require
12
+
13
+ Motion::Project::App.setup do |app|
14
+ # Use `rake config' to see complete project settings.
15
+ app.name = 'rm-extensions'
16
+ end
@@ -0,0 +1,5 @@
1
+ class AppDelegate
2
+ def application(application, didFinishLaunchingWithOptions:launchOptions)
3
+ true
4
+ end
5
+ end
@@ -1,3 +1,3 @@
1
1
  module RMExtensions
2
- VERSION = "0.1.5"
2
+ VERSION = "0.1.6"
3
3
  end
Binary file
data/spec/main_spec.rb ADDED
@@ -0,0 +1,240 @@
1
+ describe "Equation-style AutoLayout Constraints" do
2
+
3
+ def self.test_constraint_equation(c1_str, optional_desc=nil, &block)
4
+ it "#{optional_desc || c1_str}" do
5
+ c1 = @layout.eq c1_str
6
+ c2 = block.call
7
+ c1.priority.should == c2.priority
8
+ c1.firstItem.should == c2.firstItem
9
+ c1.firstAttribute.should == c2.firstAttribute
10
+ c1.relation.should == c2.relation
11
+ c1.secondItem.should == c2.secondItem
12
+ c1.secondAttribute.should == c2.secondAttribute
13
+ c1.multiplier.should == c2.multiplier
14
+ c1.constant.should == c2.constant
15
+ end
16
+ end
17
+
18
+ before do
19
+ @view = UIView.new
20
+ @label1 = UILabel.new
21
+ @label2 = UILabel.new
22
+ @layout = RMExtensions::Layout.new
23
+ @layout.view @view
24
+ @layout.subviews({
25
+ "label1" => @label1,
26
+ "label2" => @label2
27
+ })
28
+ end
29
+
30
+ test_constraint_equation("label1.left == 0") do
31
+ NSLayoutConstraint.constraintWithItem(@label1,
32
+ attribute:NSLayoutAttributeLeft,
33
+ relatedBy:NSLayoutRelationEqual,
34
+ toItem:@view,
35
+ attribute:NSLayoutAttributeLeft,
36
+ multiplier:1.0,
37
+ constant:0)
38
+ end
39
+
40
+ test_constraint_equation("label1.left == 8") do
41
+ NSLayoutConstraint.constraintWithItem(@label1,
42
+ attribute:NSLayoutAttributeLeft,
43
+ relatedBy:NSLayoutRelationEqual,
44
+ toItem:@view,
45
+ attribute:NSLayoutAttributeLeft,
46
+ multiplier:1.0,
47
+ constant:8)
48
+ end
49
+
50
+ test_constraint_equation("label1.right == -20") do
51
+ NSLayoutConstraint.constraintWithItem(@label1,
52
+ attribute:NSLayoutAttributeRight,
53
+ relatedBy:NSLayoutRelationEqual,
54
+ toItem:@view,
55
+ attribute:NSLayoutAttributeRight,
56
+ multiplier:1.0,
57
+ constant:-20)
58
+ end
59
+
60
+ test_constraint_equation("label1.top == 0") do
61
+ NSLayoutConstraint.constraintWithItem(@label1,
62
+ attribute:NSLayoutAttributeTop,
63
+ relatedBy:NSLayoutRelationEqual,
64
+ toItem:@view,
65
+ attribute:NSLayoutAttributeTop,
66
+ multiplier:1.0,
67
+ constant:0)
68
+ end
69
+
70
+ test_constraint_equation("label1.bottom == -36") do
71
+ NSLayoutConstraint.constraintWithItem(@label1,
72
+ attribute:NSLayoutAttributeBottom,
73
+ relatedBy:NSLayoutRelationEqual,
74
+ toItem:@view,
75
+ attribute:NSLayoutAttributeBottom,
76
+ multiplier:1.0,
77
+ constant:-36)
78
+ end
79
+
80
+ test_constraint_equation("label1.height == 1") do
81
+ NSLayoutConstraint.constraintWithItem(@label1,
82
+ attribute:NSLayoutAttributeHeight,
83
+ relatedBy:NSLayoutRelationEqual,
84
+ toItem:nil,
85
+ attribute:NSLayoutAttributeNotAnAttribute,
86
+ multiplier:1.0,
87
+ constant:1)
88
+ end
89
+
90
+ test_constraint_equation("label1.centerX == 0") do
91
+ NSLayoutConstraint.constraintWithItem(@label1,
92
+ attribute:NSLayoutAttributeCenterX,
93
+ relatedBy:NSLayoutRelationEqual,
94
+ toItem:@view,
95
+ attribute:NSLayoutAttributeCenterX,
96
+ multiplier:1.0,
97
+ constant:0)
98
+ end
99
+
100
+ test_constraint_equation("label1.width == 1.5") do
101
+ NSLayoutConstraint.constraintWithItem(@label1,
102
+ attribute:NSLayoutAttributeWidth,
103
+ relatedBy:NSLayoutRelationEqual,
104
+ toItem:nil,
105
+ attribute:NSLayoutAttributeNotAnAttribute,
106
+ multiplier:1.0,
107
+ constant:1.5)
108
+ end
109
+
110
+ test_constraint_equation("label1.left >= 6") do
111
+ NSLayoutConstraint.constraintWithItem(@label1,
112
+ attribute:NSLayoutAttributeLeft,
113
+ relatedBy:NSLayoutRelationGreaterThanOrEqual,
114
+ toItem:@view,
115
+ attribute:NSLayoutAttributeLeft,
116
+ multiplier:1.0,
117
+ constant:6)
118
+ end
119
+
120
+ test_constraint_equation("label1.width == 0 @ low # prefer box hugs content") do
121
+ NSLayoutConstraint.constraintWithItem(@label1,
122
+ attribute:NSLayoutAttributeWidth,
123
+ relatedBy:NSLayoutRelationEqual,
124
+ toItem:nil,
125
+ attribute:NSLayoutAttributeNotAnAttribute,
126
+ multiplier:1.0,
127
+ constant:0).tap { |x| x.priority = UILayoutPriorityDefaultLow }
128
+ end
129
+
130
+ test_constraint_equation("label1.left == 24 @ low # this button prefers to hug the left") do
131
+ NSLayoutConstraint.constraintWithItem(@label1,
132
+ attribute:NSLayoutAttributeLeft,
133
+ relatedBy:NSLayoutRelationEqual,
134
+ toItem:@view,
135
+ attribute:NSLayoutAttributeLeft,
136
+ multiplier:1.0,
137
+ constant:24).tap { |x| x.priority = UILayoutPriorityDefaultLow }
138
+ end
139
+
140
+ test_constraint_equation("label1.top == view.top + 8") do
141
+ NSLayoutConstraint.constraintWithItem(@label1,
142
+ attribute:NSLayoutAttributeTop,
143
+ relatedBy:NSLayoutRelationEqual,
144
+ toItem:@view,
145
+ attribute:NSLayoutAttributeTop,
146
+ multiplier:1.0,
147
+ constant:8)
148
+ end
149
+
150
+ test_constraint_equation("label1.left == label2.left * 0.5 - 5") do
151
+ NSLayoutConstraint.constraintWithItem(@label1,
152
+ attribute:NSLayoutAttributeLeft,
153
+ relatedBy:NSLayoutRelationEqual,
154
+ toItem:@label2,
155
+ attribute:NSLayoutAttributeLeft,
156
+ multiplier:0.5,
157
+ constant:-5)
158
+ end
159
+
160
+ test_constraint_equation("label1.top == label2.top + 5") do
161
+ NSLayoutConstraint.constraintWithItem(@label1,
162
+ attribute:NSLayoutAttributeTop,
163
+ relatedBy:NSLayoutRelationEqual,
164
+ toItem:@label2,
165
+ attribute:NSLayoutAttributeTop,
166
+ multiplier:1.0,
167
+ constant:5)
168
+ end
169
+
170
+ test_constraint_equation("label1.top == label2.bottom") do
171
+ NSLayoutConstraint.constraintWithItem(@label1,
172
+ attribute:NSLayoutAttributeTop,
173
+ relatedBy:NSLayoutRelationEqual,
174
+ toItem:@label2,
175
+ attribute:NSLayoutAttributeBottom,
176
+ multiplier:1.0,
177
+ constant:0)
178
+ end
179
+
180
+ test_constraint_equation("label1.width == label2.width @ low # the widths of the labels prefer to be the same") do
181
+ NSLayoutConstraint.constraintWithItem(@label1,
182
+ attribute:NSLayoutAttributeWidth,
183
+ relatedBy:NSLayoutRelationEqual,
184
+ toItem:@label2,
185
+ attribute:NSLayoutAttributeWidth,
186
+ multiplier:1.0,
187
+ constant:0).tap { |x| x.priority = UILayoutPriorityDefaultLow }
188
+ end
189
+
190
+ test_constraint_equation("label1.left == label2.right + 20") do
191
+ NSLayoutConstraint.constraintWithItem(@label1,
192
+ attribute:NSLayoutAttributeLeft,
193
+ relatedBy:NSLayoutRelationEqual,
194
+ toItem:@label2,
195
+ attribute:NSLayoutAttributeRight,
196
+ multiplier:1.0,
197
+ constant:20)
198
+ end
199
+
200
+ test_constraint_equation("label1.centerY == label2.centerY") do
201
+ NSLayoutConstraint.constraintWithItem(@label1,
202
+ attribute:NSLayoutAttributeCenterY,
203
+ relatedBy:NSLayoutRelationEqual,
204
+ toItem:@label2,
205
+ attribute:NSLayoutAttributeCenterY,
206
+ multiplier:1.0,
207
+ constant:0)
208
+ end
209
+
210
+ test_constraint_equation("label1.left >= label2.right + 6") do
211
+ NSLayoutConstraint.constraintWithItem(@label1,
212
+ attribute:NSLayoutAttributeLeft,
213
+ relatedBy:NSLayoutRelationGreaterThanOrEqual,
214
+ toItem:@label2,
215
+ attribute:NSLayoutAttributeRight,
216
+ multiplier:1.0,
217
+ constant:6)
218
+ end
219
+
220
+ test_constraint_equation("label1.right <= view.right - 8") do
221
+ NSLayoutConstraint.constraintWithItem(@label1,
222
+ attribute:NSLayoutAttributeRight,
223
+ relatedBy:NSLayoutRelationLessThanOrEqual,
224
+ toItem:@view,
225
+ attribute:NSLayoutAttributeRight,
226
+ multiplier:1.0,
227
+ constant:-8)
228
+ end
229
+
230
+ test_constraint_equation("label1.right <= label2.left - 10") do
231
+ NSLayoutConstraint.constraintWithItem(@label1,
232
+ attribute:NSLayoutAttributeRight,
233
+ relatedBy:NSLayoutRelationLessThanOrEqual,
234
+ toItem:@label2,
235
+ attribute:NSLayoutAttributeLeft,
236
+ multiplier:1.0,
237
+ constant:-10)
238
+ end
239
+
240
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rm-extensions
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joe Noon
@@ -22,6 +22,7 @@ files:
22
22
  - LICENSE.txt
23
23
  - README.md
24
24
  - Rakefile
25
+ - app/app_delegate.rb
25
26
  - lib/motion/accessors.rb
26
27
  - lib/motion/layout.rb
27
28
  - lib/motion/observation.rb
@@ -29,7 +30,9 @@ files:
29
30
  - lib/motion/util.rb
30
31
  - lib/rm-extensions.rb
31
32
  - lib/rm-extensions/version.rb
33
+ - resources/Default-568h@2x.png
32
34
  - rm-extensions.gemspec
35
+ - spec/main_spec.rb
33
36
  homepage: https://github.com/joenoon/rm-extensions
34
37
  licenses: []
35
38
  metadata: {}
@@ -53,4 +56,5 @@ rubygems_version: 2.0.3
53
56
  signing_key:
54
57
  specification_version: 4
55
58
  summary: Extensions and helpers for dealing with various areas of rubymotion
56
- test_files: []
59
+ test_files:
60
+ - spec/main_spec.rb