README.md in rm-extensions-0.1.5 vs README.md in rm-extensions-0.1.6
- old
+ new
@@ -1,8 +1,205 @@
RMExtensions
-----------------
-#### Extensions and helpers for dealing with various areas of rubymotion.
+#### Extensions and helpers for dealing with various areas of rubymotion and iOS.
+
+## Equation-style AutoLayout Constraints
+
+AutoLayout is a great way to lay out views, but writing constraints manually is
+confusing and verbose.
+
+Using Apple's "Visual Format Language" ASCII-inspired
+strings can improve things, but it has drawbacks: **1)** It returns an array
+of constraints. This means if you plan on altering one of them later, or removing
+one in particular, you would have to loop through all of the constraints, testing
+each one to see if its the one you want. **2)** The `options` argument adds additional
+constraints. For example, if you specify NSLayoutAttributeCenterY to a horizontal string,
+an additional constraint will be added for each view to set their centerY's equal to each
+other. This compounds problem #1. The chances you will get an error that the layout system
+cannot satisfy your constraints is probably because of these "extra" constraints. **3)**
+It can't handle complex constraints, so you end up needing to supplement it with
+verbose low-level constraint creation anyway.
+
+Apple makes note of how constraints can be thought of like a linear equation:
+
+http://developer.apple.com/library/ios/documentation/AppKit/Reference/NSLayoutConstraint_Class/NSLayoutConstraint/NSLayoutConstraint.html
+
+**Remember the formula:**
+
+```ruby
+view1.attr1 == view2.attr2 * multiplier + constant @ priority
+```
+
+**We can actually use this super-simple formula to write ALL of our constraints, simple OR complex!**
+
+Once you get the hang of the formula and visualization of how the geometry works, it becomes easy to create complex layouts with little
+effort. And, in my opinion, its only slightly more verbose than the visual format language, but much clearer, and you only end up
+with the exact constraints you want.
+
+Available values for `attr1` and `attr2` are:
+
+- left
+- right
+- top
+- bottom
+- leading
+- trailing
+- width
+- height
+- centerX
+- centerY
+- baseline
+
+Available `relation` values are:
+
+- ==
+- <=
+- >=
+
+Available `priority` values are:
+
+- required (1000 is the default)
+- high (750)
+- low (250)
+- fit (50)
+- or, you can use your own value between 1-1000
+
+
+### Examples
+
+Here is a real example. The Layout instance is created just like the motion-layout gem. `layout.view` sets the view
+that will act as the 'superview' to the views set in `layout.subviews`. Thats where the similarities end with
+motion-layout. With RMExtensions::Layout, there are two methods: `eq` and `eqs`, short for equation and equations.
+
+- `layout.eq` takes one string, and returns *one constraint*
+- `layout.eqs` takes one string, assumes multiple constraints are separated by newlines, and returns an *array of constraints*
+
+```ruby
+RMExtensions::Layout.new do |layout|
+ layout.view view
+ layout.subviews({
+ "calendar" => calendarView,
+ "table" => tableView,
+ "shadow" => line
+ })
+
+ layout.eqs %Q{
+ calendar.left == 0
+ calendar.right == 0
+ table.left == 7
+ table.right == -7
+ shadow.left == 0
+ shadow.right == 0
+
+ calendar.top == 0
+ table.top == calendar.bottom
+ table.bottom == 0
+ shadow.top == table.top
+ }
+
+ @calendar_height_constraint = layout.eq "calendar.height == 0"
+end
+```
+
+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.
+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.
+The last constraint is created separately and stored in @calendar_height_constraint, because I want to be able to change the calendar's height
+any time I want.
+
+Here is another example:
+
+```ruby
+RMExtensions::Layout.new do |layout|
+ layout.view self
+ layout.subviews({
+ "timeLabel" => @timeLabel,
+ "titleLabel" => @titleLabel,
+ "trackingImage" => @trackingImage,
+ "inOutStatusInImage" => @inOutStatusInImage,
+ "inOutStatusOutImage" => @inOutStatusOutImage,
+ "plannerImage" => @plannerImage,
+ "shareButton" => @shareButton,
+ "cancelledLabel" => @cancelledLabel,
+ "unreadImage" => @unreadImage
+ })
+
+ layout.eqs %Q{
+ unreadImage.left == 6
+ unreadImage.top == 6
+ plannerImage.left == 14
+ plannerImage.centerY == 0
+ plannerImage.width == 30
+ plannerImage.height == 30
+ trackingImage.left == timeLabel.right + 5
+ inOutStatusOutImage.left == trackingImage.right + 5
+ inOutStatusInImage.left == inOutStatusOutImage.right + 5
+ timeLabel.left == plannerImage.right + 5
+ timeLabel.baseline == plannerImage.bottom + 1
+ trackingImage.centerY == timeLabel.centerY
+ inOutStatusOutImage.centerY == timeLabel.centerY
+ inOutStatusInImage.centerY == timeLabel.centerY
+ titleLabel.left == cancelledLabel.right
+ cancelledLabel.left == plannerImage.right + 5
+ titleLabel.top == plannerImage.top - 4
+ cancelledLabel.centerY == titleLabel.centerY
+ shareButton.right == -10
+ shareButton.centerY == 0
+ titleLabel.resistH == low
+ shareButton.left >= titleLabel.right + 5
+ timeLabel.resistH == low
+ shareButton.left >= inOutStatusInImage.right + 5
+ }
+
+end
+```
+
+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,
+so don't think its odd if you can't find a use for it.
+
+There are two special cases at the moment. **titleLabel.resistH == low** is not a "real" constraint. Its a shortcut to
+`setContentCompressionResistancePriority`, and since its common when dealing with autolayout, its nice to include it
+in our layout code. The same is done for `setContentHuggingPriority`. The full list of "special cases" at the moment:
+
+- view1.resistH == priority
+- view1.resistV == priority
+- view1.hugH == priority
+- view1.hugV == priority
+
+"priority" can be one of the values listed earlier, or your own number between 1-1000.
+
+### Debugging constraints
+
+- You can include a **?** on any line, and debug output will be printed when that constraint is built:
+
+```ruby
+layout.eqs %Q{
+ label.left == photo.right + 5 ?
+}
+```
+
+- Since layout.eqs allows you to write many constraints in one string, and sometimes its nice to
+keep comments next to constraints, **comments are allowed**:
+
+```ruby
+layout.eqs %Q{
+ commentsCount.width == likesCount.width @ low # the widths of the labels prefer to be the same
+}
+```
+
+### Things to remember
+
+- 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.
+
+- The formula is just shorthand for `constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:`. You should **really** read up on constraints and
+understand this method, to fully understand the power and simplicity the shorthand formula gives you.
+
+
+
+
+
+
+
## Observation/KVO, Events
#### Make observations without needing to clean up/unobserve