sugarcube 0.20.25 → 1.0.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.
- data/Gemfile +3 -1
- data/Gemfile.lock +1 -1
- data/README.md +897 -1306
- data/Rakefile +3 -7
- data/app/uicontrol_controller.rb +2 -2
- data/lib/sugarcube-568.rb +1 -9
- data/lib/sugarcube-all.rb +18 -0
- data/lib/sugarcube-animations.rb +15 -0
- data/lib/{sugarcube → sugarcube-animations}/animation_chain.rb +0 -0
- data/lib/{sugarcube → sugarcube-animations}/uiview.rb +41 -111
- data/lib/sugarcube-anonymous.rb +1 -9
- data/lib/sugarcube-attributedstring.rb +1 -9
- data/lib/sugarcube-attributedstring/nsattributedstring.rb +2 -11
- data/lib/sugarcube-awesome.rb +15 -0
- data/lib/sugarcube-awesome/awesome_exts.rb +22 -0
- data/lib/sugarcube-classic.rb +26 -0
- data/lib/sugarcube-color.rb +15 -0
- data/lib/sugarcube-color/fixnum.rb +18 -0
- data/lib/sugarcube-color/nsarray.rb +11 -0
- data/lib/sugarcube-color/nsstring.rb +16 -0
- data/lib/{sugarcube/symbol/symbol_uicolor.rb → sugarcube-color/symbol.rb} +12 -4
- data/lib/{sugarcube → sugarcube-color}/uicolor.rb +16 -2
- data/lib/sugarcube-color/uiimage.rb +13 -0
- data/lib/sugarcube-common.rb +22 -0
- data/lib/sugarcube-constants.rb +15 -0
- data/lib/sugarcube-constants/symbol.rb +759 -0
- data/lib/sugarcube-coregraphics.rb +15 -0
- data/lib/{sugarcube → sugarcube-coregraphics}/core_graphics.rb +0 -0
- data/lib/sugarcube-corelocation.rb +17 -0
- data/lib/{sugarcube → sugarcube-corelocation}/core_location.rb +0 -0
- data/lib/sugarcube-events.rb +15 -0
- data/lib/{sugarcube → sugarcube-events}/uicontrol.rb +3 -3
- data/lib/{sugarcube → sugarcube-events}/uitextview.rb +0 -0
- data/lib/sugarcube-factories.rb +15 -0
- data/lib/{sugarcube → sugarcube-factories}/nserror.rb +0 -0
- data/lib/{sugarcube → sugarcube-factories}/uiactionsheet.rb +3 -1
- data/lib/sugarcube-factories/uiactivityindicator.rb +17 -0
- data/lib/{sugarcube → sugarcube-factories}/uialertview.rb +3 -3
- data/lib/{sugarcube → sugarcube-factories}/uibarbuttonitem.rb +19 -3
- data/lib/{sugarcube → sugarcube-factories}/uibutton.rb +10 -10
- data/lib/{sugarcube → sugarcube-factories}/uisegmentedcontrol.rb +4 -4
- data/lib/{sugarcube → sugarcube-factories}/uitableview.rb +0 -0
- data/lib/{sugarcube → sugarcube-factories}/uitableviewcell.rb +3 -7
- data/lib/sugarcube-files.rb +15 -0
- data/lib/{sugarcube/nsstring_files.rb → sugarcube-files/nsstring.rb} +0 -0
- data/lib/sugarcube-foundation.rb +15 -0
- data/lib/{sugarcube → sugarcube-foundation}/nsarray.rb +0 -18
- data/lib/sugarcube-foundation/nsindexpath.rb +13 -0
- data/lib/{sugarcube → sugarcube-foundation}/nsindexset.rb +0 -0
- data/lib/sugarcube-foundation/nsstring.rb +31 -0
- data/lib/{sugarcube → sugarcube-foundation}/nsurl.rb +0 -4
- data/lib/sugarcube-gestures.rb +1 -9
- data/lib/sugarcube-image.rb +15 -0
- data/lib/sugarcube-image/cicolor.rb +7 -0
- data/lib/sugarcube-image/cifilter.rb +772 -0
- data/lib/sugarcube-image/ciimage.rb +22 -0
- data/lib/sugarcube-image/uicolor.rb +7 -0
- data/lib/{sugarcube → sugarcube-image}/uiimage.rb +38 -41
- data/lib/sugarcube-indexpath.rb +15 -0
- data/lib/{sugarcube/nsindexpath.rb → sugarcube-indexpath/indexpath.rb} +12 -21
- data/lib/sugarcube-legacy.rb +15 -0
- data/lib/{sugarcube → sugarcube-legacy}/activesupport.rb +0 -0
- data/lib/sugarcube-legacy/log.rb +45 -0
- data/lib/sugarcube-legacy/symbol.rb +219 -0
- data/lib/sugarcube-localized.rb +15 -0
- data/lib/sugarcube-localized/nserror.rb +8 -0
- data/lib/sugarcube-localized/nsstring.rb +10 -0
- data/lib/sugarcube-modal.rb +15 -0
- data/lib/{sugarcube → sugarcube-modal}/modal.rb +0 -0
- data/lib/sugarcube-notifications.rb +15 -0
- data/lib/{sugarcube → sugarcube-notifications}/notifications.rb +0 -0
- data/lib/sugarcube-nscoder.rb +15 -0
- data/lib/{sugarcube → sugarcube-nscoder}/nscoder.rb +0 -0
- data/lib/sugarcube-nsdata.rb +15 -0
- data/lib/{sugarcube → sugarcube-nsdata}/nsdata.rb +0 -0
- data/lib/sugarcube-nsdata/nsstring.rb +9 -0
- data/lib/sugarcube-nsdata/nsurl.rb +7 -0
- data/lib/sugarcube-nsdata/uiimage.rb +8 -0
- data/lib/sugarcube-nsdate.rb +15 -0
- data/lib/{sugarcube → sugarcube-nsdate}/date_parser.rb +0 -0
- data/lib/sugarcube-nsdate/fixnum.rb +23 -0
- data/lib/{sugarcube → sugarcube-nsdate}/nsdate.rb +6 -1
- data/lib/{sugarcube → sugarcube-nsdate}/nsdate_delta.rb +0 -0
- data/lib/sugarcube-nsdate/nsstring.rb +16 -0
- data/lib/sugarcube-nsuserdefaults.rb +15 -0
- data/lib/{sugarcube → sugarcube-nsuserdefaults}/nsuserdefaults.rb +0 -0
- data/lib/sugarcube-numbers.rb +15 -0
- data/lib/sugarcube-numbers/fixnum.rb +25 -0
- data/lib/sugarcube-numbers/nsstring.rb +13 -0
- data/lib/{sugarcube → sugarcube-numbers}/numeric.rb +44 -4
- data/lib/sugarcube-osx/adjust.rb +373 -0
- data/lib/sugarcube-pipes.rb +15 -0
- data/lib/sugarcube-pipes/pipes.rb +78 -0
- data/lib/sugarcube-pointer.rb +15 -0
- data/lib/sugarcube-pointer/nsarray.rb +13 -0
- data/lib/sugarcube-repl.rb +1 -9
- data/lib/sugarcube-resources.rb +15 -0
- data/lib/sugarcube-timer.rb +15 -0
- data/lib/{sugarcube → sugarcube-timer}/timer.rb +0 -0
- data/lib/sugarcube-to_s.rb +15 -0
- data/lib/{sugarcube/to_s → sugarcube-to_s}/nserror.rb +1 -4
- data/lib/sugarcube-to_s/nsindexpath.rb +7 -0
- data/lib/{sugarcube/to_s → sugarcube-to_s}/nslayoutconstraint.rb +0 -0
- data/lib/{sugarcube/to_s → sugarcube-to_s}/nsnotification.rb +0 -0
- data/lib/{sugarcube/to_s → sugarcube-to_s}/nsset.rb +0 -0
- data/lib/{sugarcube/to_s → sugarcube-to_s}/nsurl.rb +0 -0
- data/lib/{sugarcube/to_s → sugarcube-to_s}/uicolor.rb +0 -0
- data/lib/{sugarcube/to_s → sugarcube-to_s}/uievent.rb +0 -0
- data/lib/{sugarcube/to_s → sugarcube-to_s}/uilabel.rb +0 -0
- data/lib/{sugarcube/to_s → sugarcube-to_s}/uitextfield.rb +0 -0
- data/lib/{sugarcube/to_s → sugarcube-to_s}/uitouch.rb +0 -0
- data/lib/{sugarcube/to_s → sugarcube-to_s}/uiview.rb +0 -0
- data/lib/{sugarcube/to_s → sugarcube-to_s}/uiviewcontroller.rb +0 -0
- data/lib/sugarcube-uicolor.rb +1 -0
- data/lib/sugarcube-uifont.rb +15 -0
- data/lib/sugarcube-uiimage.rb +1 -0
- data/lib/sugarcube-uikit.rb +15 -0
- data/lib/{sugarcube → sugarcube-uikit}/calayer.rb +0 -0
- data/lib/sugarcube-uikit/nsattributedstring.rb +12 -0
- data/lib/sugarcube-uikit/nsstring.rb +38 -0
- data/lib/sugarcube-uikit/symbol.rb +67 -0
- data/lib/{sugarcube → sugarcube-uikit}/uifont.rb +1 -4
- data/lib/sugarcube-uikit/uiimage.rb +9 -0
- data/lib/{sugarcube → sugarcube-uikit}/uilabel.rb +0 -0
- data/lib/{sugarcube → sugarcube-uikit}/uipickerview.rb +0 -0
- data/lib/sugarcube-uikit/uiview.rb +100 -0
- data/lib/{sugarcube → sugarcube-uikit}/uiviewcontroller.rb +0 -0
- data/lib/{sugarcube → sugarcube-uikit}/uiwebview.rb +0 -0
- data/lib/sugarcube-unholy.rb +1 -9
- data/lib/sugarcube.rb +4 -9
- data/lib/sugarcube/adjust.rb +1 -0
- data/lib/sugarcube/look_in.rb +22 -0
- data/lib/sugarcube/version.rb +1 -1
- data/runtests +1 -1
- data/spec/{uicolor_components_spec.rb → color_components_spec.rb} +0 -0
- data/spec/{uicolor_other_representations_spec.rb → color_other_representations_spec.rb} +0 -0
- data/spec/{uicolor_spec.rb → color_spec.rb} +0 -0
- data/spec/image_cifilters_spec.rb +549 -0
- data/spec/{uiimage_color_at_spec.rb → image_color_at_spec.rb} +0 -0
- data/spec/{uiimage_scale_spec.rb → image_scale_spec.rb} +0 -0
- data/spec/image_uiimage_filters_spec.rb +47 -0
- data/spec/nsdate_spec.rb +11 -0
- data/spec/nsurl_spec.rb +1 -1
- data/spec/numeric_spec.rb +10 -0
- data/spec/pipes_spec.rb +135 -0
- data/spec/sugarcube_legacy.rb +59 -0
- data/spec/symbol_constants_spec.rb +809 -0
- data/spec/symbol_uicolor_spec.rb +20 -4
- data/spec/symbol_uifont_spec.rb +30 -0
- data/spec/uiactionsheet_spec.rb +1 -1
- data/spec/uialertview_spec.rb +1 -1
- data/spec/uibarbuttonitem_spec.rb +46 -46
- data/sugarcube.gemspec +1 -1
- metadata +142 -74
- data/lib/sugarcube/exceptions.rb +0 -2
- data/lib/sugarcube/fixnum.rb +0 -59
- data/lib/sugarcube/nsstring.rb +0 -107
- data/lib/sugarcube/symbol.rb +0 -766
- data/lib/sugarcube/uiactivityindicator.rb +0 -17
- data/lib/sugarcube/uuid.rb +0 -10
- data/spec/activesupport_spec.rb +0 -96
- data/spec/symbol_spec.rb +0 -32
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
SugarCube
|
|
2
2
|
=========
|
|
3
3
|
|
|
4
|
-
Some sugar for your cocoa, or your [tea][sweettea].
|
|
4
|
+
Some sugar for your [cocoa](http://rubymotion.com), or your [tea][sweettea].
|
|
5
5
|
|
|
6
6
|
[](https://travis-ci.org/rubymotion/sugarcube)
|
|
7
7
|
|
|
@@ -9,15 +9,14 @@ About
|
|
|
9
9
|
-----
|
|
10
10
|
|
|
11
11
|
CocoaTouch/iOS is a *verbose* framework. These extensions hope to make
|
|
12
|
-
development in rubymotion more enjoyable
|
|
13
|
-
|
|
14
|
-
integer or symbol, or create a UIFont or UIImage from a string.
|
|
12
|
+
development in rubymotion more enjoyable. With SugarCube, you can create a color
|
|
13
|
+
from an integer or symbol, or create a UIFont or UIImage from a string.
|
|
15
14
|
|
|
16
|
-
Some
|
|
17
|
-
instance, instead of view.addSubview(subview), you can use the more
|
|
18
|
-
view << subview.
|
|
15
|
+
Some core classes are opened up as well, like adding the '<<' operator to a
|
|
16
|
+
UIView instance, instead of view.addSubview(subview), you can use the more
|
|
17
|
+
idiomatic: view << subview.
|
|
19
18
|
|
|
20
|
-
The basic idea of SugarCube is to turn
|
|
19
|
+
The basic idea of SugarCube is to turn operations on their head. So instead of:
|
|
21
20
|
|
|
22
21
|
UIApplication.sharedApplication.openURL(NSURL.URLWithString(url))
|
|
23
22
|
|
|
@@ -49,6 +48,7 @@ diligent about adding Yard documentation, which is available here:
|
|
|
49
48
|
|
|
50
49
|
<http://rubydoc.info/gems/sugarcube/latest>
|
|
51
50
|
|
|
51
|
+
[documentation]: http://rubydoc.info/gems/sugarcube/latest
|
|
52
52
|
|
|
53
53
|
Installation
|
|
54
54
|
============
|
|
@@ -59,554 +59,353 @@ Installation
|
|
|
59
59
|
require 'sugarcube'
|
|
60
60
|
|
|
61
61
|
# or in Gemfile
|
|
62
|
-
gem 'sugarcube'
|
|
62
|
+
gem 'sugarcube', :require => 'sugarcube-classic'
|
|
63
|
+
# or for the bold:
|
|
64
|
+
# gem 'sugarcube', :require => 'sugarcube-all'
|
|
63
65
|
|
|
64
66
|
# in terminal
|
|
65
67
|
$ bundle install
|
|
66
68
|
|
|
67
|
-
|
|
69
|
+
Packages
|
|
68
70
|
========
|
|
69
71
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
+
SugarCube has grown over time to be a pretty massive collection of helpers.
|
|
73
|
+
While some people choose to use the entire library, other people like to pick
|
|
74
|
+
and choose the extensions they want to use. With that in mind, SugarCube is
|
|
75
|
+
written so that it does *not* pollute any classes by default. So if all you do
|
|
76
|
+
is `require "sugarcube"`, you are NOT going to get much mileage!
|
|
77
|
+
|
|
78
|
+
In the installation code above, I show the example of using `:require => 'sugarcube-all'`
|
|
79
|
+
to include *all* of SugarCube's extensions. Usually you will require the
|
|
80
|
+
packages you need from your Rakefile:
|
|
72
81
|
|
|
73
82
|
```ruby
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
83
|
+
$:.unshift('/Library/RubyMotion/lib')
|
|
84
|
+
require 'motion/project/template/ios'
|
|
85
|
+
require 'bundler'
|
|
86
|
+
Bundler.require
|
|
87
|
+
require './lib/sugarcube-uikit'
|
|
88
|
+
require './lib/sugarcube-events'
|
|
89
|
+
require './lib/sugarcube-gestures'
|
|
90
|
+
require './lib/sugarcube-568'
|
|
91
|
+
require './lib/sugarcube-attributedstring'
|
|
92
|
+
# ...
|
|
77
93
|
```
|
|
78
94
|
|
|
79
|
-
|
|
80
|
-
|
|
95
|
+
You can require the packages in piecemeal like this, or you can require a group
|
|
96
|
+
of packages: `classic, common, or all`.
|
|
81
97
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
98
|
+
* `sugarcube-classic`: Excludes **568**, **attributedstring**, **gestures**, **repl**, **awesome**, **anonymous**, **unholy**, and **legacy**
|
|
99
|
+
* `sugarcube-common`: Excludes **awesome**, **anonymous**, **unholy**, and **legacy**
|
|
100
|
+
* `sugarcube-all`: Excludes **legacy**
|
|
85
101
|
|
|
86
|
-
|
|
87
|
-
accessed using method names. Uses the `SugarCube::Anonymous` class to
|
|
88
|
-
accomplish this, though the usual interface is via `Hash#to_object`.
|
|
102
|
+
So without further ado,
|
|
89
103
|
|
|
90
|
-
|
|
91
|
-
|
|
104
|
+
SugarCube
|
|
105
|
+
=========
|
|
92
106
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
h.bar # => h['bar']
|
|
96
|
-
h.foo = 'Foo' # => h[:foo] = 'Foo'
|
|
97
|
-
h.bar = 'Bar' # => h['bar'] = 'Bar'
|
|
107
|
+
Packages are sorted more-or-less by their usefulness. The more esoteric ones
|
|
108
|
+
are at the end.
|
|
98
109
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
h.baz = 'baz' # => NoMethodError
|
|
102
|
-
```
|
|
110
|
+
REPL ([wiki][REPL Wiki])
|
|
111
|
+
----
|
|
103
112
|
|
|
104
|
-
|
|
105
|
-
|
|
113
|
+
If you install SugarCube and *only* use the REPL package, you will benefit from
|
|
114
|
+
some of its greatest tools!
|
|
106
115
|
|
|
107
|
-
|
|
108
|
-
# create a UIColor from a hex value
|
|
109
|
-
0xffffff.uicolor # => UIColor.colorWithRed(1.0, green:1.0, blue:1.0, alpha:1.0)
|
|
110
|
-
0xffffff.uicolor(0.5) # => UIColor.colorWithRed(1.0, green:1.0, blue:1.0, alpha:0.5)
|
|
116
|
+
> `require 'sugarcube-repl'`
|
|
111
117
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
3.nth # => 'rd'
|
|
116
|
-
4.nth # => 'th'
|
|
117
|
-
11.nth # => 'th'
|
|
118
|
-
13.nth # => 'th'
|
|
119
|
-
21.nth # => 'st'
|
|
120
|
-
23.nth # => 'rd'
|
|
118
|
+
This package is useful during development because it adds methods to the REPL
|
|
119
|
+
that make adjusting and introspecting views much easier. You'll get a lot more
|
|
120
|
+
done in the REPL with these additions.
|
|
121
121
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
5.days.hence # => 2013-01-08 11:42:24 -0700
|
|
126
|
-
5.days.after(NSDate.new) # => 2013-01-08 11:42:24 -0700
|
|
127
|
-
# don't confuse 'after' and 'later'
|
|
128
|
-
# after => NSDate
|
|
129
|
-
# later => NSTimer
|
|
130
|
-
```
|
|
122
|
+
To keep this document lean-and-mean, I've put most of the REPL documentation [in
|
|
123
|
+
the wiki][REPL Wiki], but a
|
|
124
|
+
quick overview:
|
|
131
125
|
|
|
132
|
-
|
|
133
|
-
|
|
126
|
+
* Use the `tree` commands to output your view hierarchy. It can accept a UIView,
|
|
127
|
+
`UIViewController`, or `CALayer` object as the root object, or it defaults to
|
|
128
|
+
your application's `UIWindow` object.
|
|
134
129
|
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
130
|
+
```
|
|
131
|
+
(main)> tree
|
|
132
|
+
0: . UIWindow(#6e1f950: [[0.0, 0.0], [320.0, 480.0]])
|
|
133
|
+
1: `-- UIView(#8b203b0: [[0.0, 20.0], [320.0, 460.0]])
|
|
134
|
+
2: +-- UIButton(#d028de0: [[10.0, 10.0], [320.0, 463.400512695312]])
|
|
135
|
+
```
|
|
136
|
+
* The number can be passed to the `adjust` method, aliased to `a`, and that will
|
|
137
|
+
become the view or object you are adjusting.
|
|
139
138
|
|
|
140
|
-
|
|
141
|
-
|
|
139
|
+
```
|
|
140
|
+
(main)> a 2
|
|
141
|
+
=> UIButton(#d028de0: [[10.0, 10.0], [320.0, 463.400512695312]])
|
|
142
|
+
```
|
|
142
143
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
0.5.pi # => 0.5 * Math::PI
|
|
144
|
+
* Now you can modify that view, either by accessing it via `a` (with no
|
|
145
|
+
arguments it returns the object being adjusted) or by using an adjust method:
|
|
146
146
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
#
|
|
151
|
-
|
|
147
|
+
```
|
|
148
|
+
> up 1
|
|
149
|
+
> wider 15
|
|
150
|
+
# these have shorthands, too
|
|
151
|
+
> u 1
|
|
152
|
+
> w 15
|
|
153
|
+
```
|
|
152
154
|
|
|
153
|
-
|
|
154
|
-
10000.string_with_style # => "10,000"
|
|
155
|
-
10000.string_with_style(NSNumberFormatterCurrencyStyle) # => "$10,000.00"
|
|
156
|
-
10000.string_with_style(:currency) # => "$10,000.00"
|
|
157
|
-
```
|
|
155
|
+
Be sure to read more in the [REPL Adjustments][REPL Wiki] Wiki page.
|
|
158
156
|
|
|
159
|
-
|
|
160
|
-
---------
|
|
157
|
+
[REPL Wiki]: https://github.com/rubymotion/sugarcube/wiki/REPL-Additions
|
|
161
158
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
```
|
|
159
|
+
UIKit ([wiki][UIKit Wiki])
|
|
160
|
+
-----
|
|
165
161
|
|
|
166
|
-
|
|
167
|
-
supported attributes (in theory they are all supported, but there's weird
|
|
168
|
-
issues with missing constants).
|
|
162
|
+
A big package chock full of methods to make working in UIKit a joy.
|
|
169
163
|
|
|
170
|
-
|
|
171
|
-
'test'.nsattributedstring({}) #=> NSAttributedString.alloc.initWithString('test', attributes:{})
|
|
172
|
-
'test'.attrd # => alias for `nsattributedstring`
|
|
173
|
-
'test'.bold # => NSAttributedString.alloc.initWithString('test', attributes:{NSFontAttributeName => :bold.uifont})
|
|
174
|
-
'test'.italic # => NSAttributedString.alloc.initWithString('test', attributes:{NSFontAttributeName => :italic.uifont})
|
|
175
|
-
'test'.underline # => NSAttributedString.alloc.initWithString('test', attributes:{NSUnderlineStyleAttributeName => NSUnderlineStyleSingle})
|
|
164
|
+
> `require 'sugarcube-uikit'`
|
|
176
165
|
|
|
177
|
-
|
|
178
|
-
'test'.bold.underline
|
|
179
|
-
# If you look up NSAttributedString Application Kit Additions, you can see all
|
|
180
|
-
# the constants. Each of those has a method on NSAttributedString.
|
|
166
|
+
A few varieties of methods are in this package:
|
|
181
167
|
|
|
182
|
-
|
|
183
|
-
|
|
168
|
+
* Conversions: `'string-to'.uiimage`, `image.uiimageview`
|
|
169
|
+
* Helpers: shorthands for common operations, like `a_view << a_subview`
|
|
170
|
+
* Symbols: `:system.uifont(20)`, `:label.uifontsize`
|
|
184
171
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
172
|
+
There are too many methods to define here. Instead: a complete list of methods
|
|
173
|
+
is available in the [documentation][], and the [wiki page][UIKit Wiki] is a
|
|
174
|
+
great source as well.
|
|
188
175
|
|
|
189
|
-
|
|
176
|
+
[UIKit Wiki]: https://github.com/rubymotion/sugarcube/wiki/UIKit
|
|
190
177
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
"and this is " + "CRAZY".italic + "\n"
|
|
194
|
-
"But here's my " + "id_rsa.pub".monospace + " file,\n" +
|
|
195
|
-
"so give me SSH access.").uilabel
|
|
196
|
-
```
|
|
178
|
+
Constants
|
|
179
|
+
-----
|
|
197
180
|
|
|
198
|
-
|
|
199
|
-
---------
|
|
181
|
+
> `require 'sugarcube-constants'`
|
|
200
182
|
|
|
201
|
-
|
|
183
|
+
There are lots and lots of constants in UIKit, so many that I wanted a way to
|
|
184
|
+
write these as symbols instead of UILongConstantNames. This package adds
|
|
185
|
+
methods to `Symbol`s to convert them into a UIKit or Foundation constant.
|
|
202
186
|
|
|
203
187
|
```ruby
|
|
204
|
-
#
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
#
|
|
209
|
-
#
|
|
210
|
-
|
|
211
|
-
self.sugarcube_is_neat = decoder.bool('sugarcube_is_neat')
|
|
188
|
+
:center.uialignment # => UITextAlignmentCenter
|
|
189
|
+
:upside_down.uiorientation # => UIDeviceOrientationPortraitUpsideDown
|
|
190
|
+
:rounded.uibuttontype # => UIButtonTypeRoundedRect
|
|
191
|
+
:highlighted.uicontrolstate # => UIControlStateHighlighted
|
|
192
|
+
:touch.uicontrolevent # => UIControlEventTouchUpInside
|
|
193
|
+
:change.uicontrolevent # => UIControlEventValueChanged
|
|
194
|
+
:all.uicontrolevent # => UIControlEventAllEvents
|
|
212
195
|
|
|
213
|
-
|
|
214
|
-
|
|
196
|
+
# these are really handy for custom buttons - touch_start means the finger is
|
|
197
|
+
# inside the button, touch_stop is outside the button or canceled
|
|
198
|
+
:touch_start # => UIControlEventTouchDown | UIControlEventTouchDragEnter
|
|
199
|
+
:touch_stop # => UIControlEventTouchUpInside | UIControlEventTouchCancel | UIControlEventTouchDragExit
|
|
215
200
|
|
|
216
|
-
#
|
|
217
|
-
|
|
218
|
-
coder.set(key, toDouble:value)
|
|
219
|
-
coder.set(key, toFloat:value)
|
|
220
|
-
coder.set(key, toInt:value)
|
|
221
|
-
coder.set(key, toPoint:value)
|
|
222
|
-
coder.set(key, toRect:value)
|
|
223
|
-
coder.set(key, toSize:value)
|
|
201
|
+
:large.uiactivityindicatorstyle # :large, :white, :gray
|
|
202
|
+
:bar.uisegmentedstyle # :plain, :bordered, :bar, :bezeled
|
|
224
203
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
decoder.size(key)
|
|
204
|
+
# UITableView and UITableViewCell have LOTS of associated constants... I'm
|
|
205
|
+
# adding them as I come across them.
|
|
206
|
+
:automatic.uitablerowanimation # or .uitableviewrowanimation
|
|
207
|
+
:default.uitablecellstyle # or .uitableviewcellstyle
|
|
208
|
+
:disclosure.uitablecellaccessory # or .uitableviewcellaccessorytype
|
|
209
|
+
:blue.uitablecellselectionstyle # or .uitableviewcellselectionstyle
|
|
232
210
|
```
|
|
233
211
|
|
|
234
|
-
|
|
235
|
-
------
|
|
212
|
+
See the complete list by browsing the [documentation][], or open up [symbol.rb][].
|
|
236
213
|
|
|
237
|
-
|
|
214
|
+
[symbol.rb]: https://github.com/rubymotion/sugarcube/blob/master/lib/sugarcube-constants/symbol.rb
|
|
238
215
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
image = 'an image'.uiimage
|
|
242
|
-
image_data = image.nsdata # PNG data representation
|
|
216
|
+
Timer
|
|
217
|
+
-----
|
|
243
218
|
|
|
244
|
-
|
|
245
|
-
image_data.nsimage # => whatever 'an image' was
|
|
246
|
-
```
|
|
219
|
+
> `require 'sugarcube-timer'`
|
|
247
220
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
`NSDate` objects are converted to `Time` objects automatically by rubymotion.
|
|
252
|
-
That's the good news.
|
|
253
|
-
The bad news? That still doesn't help a lot with some of
|
|
254
|
-
the everyday date & time crap we have to deal with. (I hate dates, especially
|
|
255
|
-
recurring events)
|
|
256
|
-
##### NSDate
|
|
257
|
-
|
|
258
|
-
1. Adds the following methods to get date and time components: `date_array, time_array, datetime_array`.
|
|
259
|
-
These methods return arrays. Comparing dates, times, or both become
|
|
260
|
-
simple `date1.date_array == date2.date_array`.
|
|
261
|
-
2. While I would love to support `date + 1.month` and have that support "smart"
|
|
262
|
-
calendar math (e.g. "2/13/2013" + 1.month => "3/13/2013"), I can't fudge with
|
|
263
|
-
the return value of `1.month` (=> `Fixnum`), and I won't make the terrible
|
|
264
|
-
assumption that "30 days of seconds is *about* one month". So instead, a new
|
|
265
|
-
method that accepts date components as options is introduced: `date.delta(months:1)`
|
|
266
|
-
3. Checking whether two dates are the same, ignoring the time components, is often required
|
|
267
|
-
`start_of_day` and `end_of_day` methods help
|
|
268
|
-
you here. They are akin to `floor` and `ceil`; if you consider the time to
|
|
269
|
-
be the "floating" component, and the date to be the nearest "integer".
|
|
270
|
-
4. Formatting is made easier with `NSDate#string_with_style(NSDateStyleConstant or Symbol for date, time)`
|
|
271
|
-
and `NSDate#string_with_format(format_string)`. See
|
|
272
|
-
<http://www.unicode.org/reports/tr35/tr35-25.html#Date_Format_Patterns> for
|
|
273
|
-
the formatters, they take getting used to, coming from `strftime`, but they
|
|
274
|
-
are much more powerful and locale-aware.
|
|
275
|
-
5. Miscellaneous other helpers. I'll go over these first.
|
|
276
|
-
|
|
277
|
-
###### Helpers
|
|
221
|
+
Methods get added to the Fixnum class, and are available as methods on
|
|
222
|
+
`NSTimer`, *and* can be called via the SugarCube::Timer module.
|
|
278
223
|
|
|
279
224
|
```ruby
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
(main)> feb_1_2012 = NSDate.from_components(year: 2012, month: 2, day:1)
|
|
289
|
-
=> 2012-02-01 00:00:00 -0700
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
(main)> feb_1_2013.timezone.name
|
|
293
|
-
=> "America/Denver"
|
|
294
|
-
(main)> feb_1_2013.era
|
|
295
|
-
=> 1 # no, I don't know what this is :-/
|
|
296
|
-
(main)> feb_1_2013.today?
|
|
297
|
-
=> false # actually, at the time I am WRITING this, it IS true, but by the time
|
|
298
|
-
# you read it, not so much ;-)
|
|
299
|
-
(main)> NSDate.new.today?
|
|
300
|
-
=> true
|
|
301
|
-
(main)> feb_1_2013.same_day?(NSDate.new)
|
|
302
|
-
=> false
|
|
303
|
-
(main)> feb_1_2013.same_day?(feb_1_2013_sometime_later)
|
|
304
|
-
# even though the time is different!?
|
|
305
|
-
=> true
|
|
306
|
-
(main)> feb_1_2013.utc_offset
|
|
307
|
-
=> -25200
|
|
308
|
-
(main)> feb_1_2013.leap_year?
|
|
309
|
-
=> false
|
|
310
|
-
(main)> NSDate.from_components(year: 2012).leap_year?
|
|
311
|
-
=> true
|
|
312
|
-
(main)> feb_1_2013.start_of_day
|
|
313
|
-
=> 2013-02-01 00:00:00 -0700
|
|
314
|
-
(main)> feb_1_2013.end_of_day
|
|
315
|
-
# NOTE! end_of_day is the NEXT DAY. this is not an accident, it makes comparisons cleaner. deal with it.
|
|
316
|
-
=> 2013-02-02 00:00:00 -0700
|
|
317
|
-
(main)> feb_1_2013.start_of_week # in the USA, start of week is Sunday
|
|
318
|
-
=> 2013-01-27 00:00:00 -0700
|
|
319
|
-
=> 2013-01-28 00:00:00 -0700 # in most other countries you will get Monday
|
|
320
|
-
(main)> feb_1_2013.start_of_week(:monday) # or you can specify it!
|
|
321
|
-
=> 2013-01-28 00:00:00 -0700
|
|
322
|
-
(main)> feb_1_2013.end_of_week # Just like end_of_day, end_of_week returns midnight of the *next day*
|
|
323
|
-
=> 2013-02-03 00:00:00 -0700
|
|
324
|
-
(main)> feb_1_2013.end_of_week(:monday)
|
|
325
|
-
=> 2013-02-04 00:00:00 -0700
|
|
326
|
-
(main)> feb_1_2013.days_in_month
|
|
327
|
-
=> 28
|
|
328
|
-
(main)> feb_1_2013.days_in_year
|
|
329
|
-
=> 365
|
|
330
|
-
(main)> feb_1_2012.days_in_month
|
|
331
|
-
=> 29
|
|
332
|
-
(main)> feb_1_2012.days_in_year
|
|
333
|
-
=> 366
|
|
334
|
-
|
|
335
|
-
(main)> now.date_array
|
|
336
|
-
=> [2012, 9, 13]
|
|
337
|
-
(main)> now.time_array
|
|
338
|
-
=> [9, 19, 6]
|
|
339
|
-
(main)> now.datetime_array
|
|
340
|
-
=> [2012, 9, 13, 9, 19, 6]
|
|
341
|
-
```
|
|
342
|
-
|
|
343
|
-
Use `NSDate#string_with_style` to generate date and/or time strings.
|
|
225
|
+
# once
|
|
226
|
+
1.second.later do
|
|
227
|
+
@view.shake
|
|
228
|
+
end
|
|
229
|
+
# repeating
|
|
230
|
+
1.second.every do
|
|
231
|
+
@view.shake
|
|
232
|
+
end
|
|
344
233
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
=> "1/29/13"
|
|
352
|
-
(main)> now.string_with_style(NSDateFormatterMediumStyle, NSDateFormatterShortStyle)
|
|
353
|
-
=> "Jan 29, 2013, 9:19 AM"
|
|
354
|
-
(main)> now.string_with_style(:short, :medium)
|
|
355
|
-
=> "1/29/13, 9:19:06 AM"
|
|
356
|
-
(main)> now.string_with_style(:none, :long)
|
|
357
|
-
=> "9:19:06 AM GMT+01:00"
|
|
358
|
-
```
|
|
234
|
+
# you can assign the return value (an NSTimer)
|
|
235
|
+
timer = 1.second.every do
|
|
236
|
+
@view.shake
|
|
237
|
+
end
|
|
238
|
+
# and invalidate it
|
|
239
|
+
timer.invalidate
|
|
359
240
|
|
|
360
|
-
|
|
361
|
-
|
|
241
|
+
# the `every` method is available in the SugarCube::Timer module,
|
|
242
|
+
# which you might find more readable
|
|
243
|
+
include SugarCube::Timer
|
|
362
244
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
(main)> now - 5
|
|
367
|
-
=> 2012-09-13 09:19:01 -0600
|
|
368
|
-
(main)> now + 5.minutes
|
|
369
|
-
=> 2012-09-13 09:24:06 -0600
|
|
370
|
-
(main)> now + 5.days
|
|
371
|
-
=> 2012-09-18 09:19:06 -0600
|
|
372
|
-
```
|
|
245
|
+
every 1.minute do
|
|
246
|
+
puts "tick"
|
|
247
|
+
end
|
|
373
248
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
249
|
+
# might as well make an alias for 'later', too
|
|
250
|
+
after 1.minute do
|
|
251
|
+
puts "ding!"
|
|
252
|
+
end
|
|
378
253
|
|
|
379
|
-
|
|
380
|
-
(
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
254
|
+
# other time-related methods
|
|
255
|
+
# for compatibility with Time methods, the mins/secs (and min/sec) aliases are provided. Personally,
|
|
256
|
+
# I like the more verbose minutes/seconds.
|
|
257
|
+
1.millisecond || 2.milliseconds
|
|
258
|
+
1.millisec || 2.millisecs
|
|
259
|
+
1.second || 2.seconds
|
|
260
|
+
1.sec || 2.secs # aliases
|
|
261
|
+
1.minute || 2.minutes # 1.minute = 60 seconds
|
|
262
|
+
1.min || 2.mins # aliases
|
|
263
|
+
1.hour || 2.hours # 1.hour = 60 minutes
|
|
264
|
+
1.day || 2.days # 1.day = 24 hours
|
|
265
|
+
1.week || 2.weeks # 1.week = 7 days
|
|
266
|
+
# sensible values for 'month' and 'year', even though we all know you can't
|
|
267
|
+
# **really** define them this way (go back to python if you find your brain hemorrhaging):
|
|
268
|
+
1.month || 2.months # 1.month = 30 days
|
|
269
|
+
1.year || 2.years # 1.year = 365 days
|
|
388
270
|
```
|
|
389
271
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
on.
|
|
272
|
+
Events
|
|
273
|
+
-----
|
|
393
274
|
|
|
394
|
-
|
|
395
|
-
(main)> feb_28_2012 = NSDate.from_components(year:2012, month: 2, day: 28)
|
|
396
|
-
=> 2012-02-28 17:00:00 -0700
|
|
397
|
-
|
|
398
|
-
# add an hour or two
|
|
399
|
-
(main)> feb_28_2012.delta(hours:1)
|
|
400
|
-
=> 2012-02-28 18:00:00 -0700
|
|
401
|
-
(main)> feb_28_2012.delta(hours:2)
|
|
402
|
-
=> 2012-02-28 19:00:00 -0700
|
|
403
|
-
|
|
404
|
-
# add some days
|
|
405
|
-
(main)> feb_28_2012.delta(days:1)
|
|
406
|
-
=> 2012-02-29 17:00:00 -0700
|
|
407
|
-
(main)> feb_28_2012.delta(days:2)
|
|
408
|
-
=> 2012-03-01 17:00:00 -0700
|
|
409
|
-
|
|
410
|
-
# how about a month?
|
|
411
|
-
(main)> feb_28_2012.delta(months:1)
|
|
412
|
-
=> 2012-03-28 17:00:00 -0600 # look, the time didn't change, event though there was a DST change in this period!
|
|
413
|
-
|
|
414
|
-
# cool, but if you want a more literal "24 hours", specify a time unit
|
|
415
|
-
(main)> feb_28_2012.delta(months:1, hours:0)
|
|
416
|
-
=> 2012-03-28 18:00:00 -0600 # disable the DST fix by specifying hours, minutes, or seconds (a "precise" delta)
|
|
417
|
-
|
|
418
|
-
# in one year, it will still be Feb 28th
|
|
419
|
-
(main)> feb_28_2012.delta(years:1)
|
|
420
|
-
=> 2013-02-28 17:00:00 -0700
|
|
421
|
-
|
|
422
|
-
# and we already know what adding a day looks like
|
|
423
|
-
(main)> feb_28_2012.delta(days:1)
|
|
424
|
-
=> 2012-02-29 17:00:00 -0700
|
|
425
|
-
|
|
426
|
-
# a year and a day is tricky, because do we add a day, then a year? or add a
|
|
427
|
-
# year and then a day? well, i'll tell you, **I** add a day and then a year,
|
|
428
|
-
# which is feb 29th, which is no good, and the algorithm rolls back days to the
|
|
429
|
-
# last day of the month, so we get the 28th.
|
|
430
|
-
(main)> feb_28_2012.delta(days:1, years:1)
|
|
431
|
-
=> 2013-02-28 17:00:00 -0700
|
|
432
|
-
|
|
433
|
-
# adding 2 days puts us into March, which then "looks right", but it's both
|
|
434
|
-
# right AND wrong, depending on how you look at it. Another example is below,
|
|
435
|
-
# where we add a month to January 30th. Really, though, think of this: how
|
|
436
|
-
# often do you need to add a year AND a day!? Adding a year is more common, and
|
|
437
|
-
# this is showing that adding a year to Feb 29th will give you Feb 28th, which I
|
|
438
|
-
# think is better than March 1st.
|
|
439
|
-
(main)> feb_28_2012.delta(days:2, years:1)
|
|
440
|
-
=> 2013-03-01 17:00:00 -0700
|
|
441
|
-
|
|
442
|
-
# Crazier: add a day (Feb 29th), then a month (March 29th), THEN a year.
|
|
443
|
-
(main)> feb_28_2012.delta(days:1, years:1, months:1)
|
|
444
|
-
=> 2013-03-29 17:00:00 -0600
|
|
445
|
-
|
|
446
|
-
# k, for the next examples, we need a new date, and this is a non-leap year.
|
|
447
|
-
(main)> jan_29_2013 = feb_28_2012.delta(days:1, months:11)
|
|
448
|
-
=> 2013-01-29 17:00:00 -0700
|
|
449
|
-
|
|
450
|
-
# what is 1/29/2013 plus two months? easy! march 29, 2013
|
|
451
|
-
(main)> jan_29_2013.delta(months:2)
|
|
452
|
-
=> 2013-03-29 17:00:00 -0600
|
|
453
|
-
|
|
454
|
-
# Yeah, smart guy? Well then what is 1/29/2013 plus ONE month. It's Feb 28th.
|
|
455
|
-
# When someone says "see you in a month!" they mean "next month", not "in the
|
|
456
|
-
# early part of two months in the future", which is where the math will take you
|
|
457
|
-
# if you don't add a "day of month" correction.
|
|
458
|
-
(main)> jan_29_2013.delta(months:1)
|
|
459
|
-
=> 2013-02-28 17:00:00 -0700
|
|
460
|
-
# but last year was a leap year, so we should get Feb 29th, 2012:
|
|
461
|
-
(main)> jan_29_2013.delta(months:1, years: -1)
|
|
462
|
-
=> 2012-02-29 17:00:00 -0700 # success!
|
|
463
|
-
|
|
464
|
-
# do other deltas work in reverse? fuuuuuu...
|
|
465
|
-
(main)> jan_29_2013.delta(months:-11)
|
|
466
|
-
=> 2012-02-29 17:00:00 -0700
|
|
467
|
-
# ...ck yeah! :-)
|
|
468
|
-
|
|
469
|
-
# daylight savings!? GEEZ dates are annoying
|
|
470
|
-
(main)> mar_10_2013 = NSDate.from_components
|
|
471
|
-
|
|
472
|
-
# unfortunately you will, in the edge cases, end up with stuff like this:
|
|
473
|
-
(main)> feb_28_2012 == feb_28_2012.delta(days:1, months:12).delta(days: -1, months:-12)
|
|
474
|
-
=> 2012-02-29 00:00:00 -0700
|
|
475
|
-
```
|
|
275
|
+
> `require 'sugarcube-events'`
|
|
476
276
|
|
|
477
|
-
|
|
478
|
-
|
|
277
|
+
Inspired by [BubbleWrap's][BubbleWrap] `when` method, but I prefer jQuery-style
|
|
278
|
+
verbs and SugarCube symbols. Adds methods to UIControl and UITextView.
|
|
479
279
|
|
|
480
|
-
|
|
280
|
+
UIControl
|
|
281
|
+
-----------
|
|
481
282
|
|
|
482
283
|
```ruby
|
|
483
|
-
|
|
484
|
-
# with options
|
|
485
|
-
NSError.new('Error Message', code: 404)
|
|
486
|
-
|
|
487
|
-
# error messages ('Error Message' in this example) are stored in a Hash with the
|
|
488
|
-
# key 'NSLocalizedDescriptionKey'. If you pass a `userInfo` option, it will get
|
|
489
|
-
# merged with this array. So you can ignore that ugly-looking key.
|
|
490
|
-
NSError.new('Error Message', code: 404, userInfo: { warnings: ['blabla'] })
|
|
491
|
-
```
|
|
284
|
+
button = UIButton.alloc.initWithFrame([0, 0, 10, 10])
|
|
492
285
|
|
|
493
|
-
|
|
494
|
-
|
|
286
|
+
button.on(:touch) { my_code }
|
|
287
|
+
button.on(:touch_up_outside, :touch_cancel) { |event|
|
|
288
|
+
puts event.inspect
|
|
289
|
+
# my_code...
|
|
290
|
+
}
|
|
495
291
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
292
|
+
# remove handlers
|
|
293
|
+
button.off(:touch, :touch_up_outside, :touch_cancel)
|
|
294
|
+
button.off(:all)
|
|
499
295
|
```
|
|
500
296
|
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
```ruby
|
|
505
|
-
# UIImage from name
|
|
506
|
-
"my_image".uiimage # => UIImage.imageNamed("my_image")
|
|
507
|
-
"pattern".uicolor == "pattern".uiimage.uicolor # => UIColor.colorWithPatternImage(UIImage.imageNamed("pattern"))
|
|
508
|
-
|
|
509
|
-
# UIFont from name
|
|
510
|
-
"my_font".uifont # => UIFont.fontWithName("my_font", size:UIFont.systemFontSize)
|
|
511
|
-
"my_font".uifont(20) # => UIFont.fontWithName("my_font", size:20)
|
|
297
|
+
You can only remove handlers by "type", not by the action. e.g. If you bind
|
|
298
|
+
three `:touch` events, calling `button.off(:touch)` will remove all three.
|
|
512
299
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
"#ff00ff".uicolor == :fuchsia.uicolor == 0xff00ff.uicolor # => UIColor.colorWithRed(1.0, green:0.0, blue:1.0, alpha:1.0)
|
|
516
|
-
"#f0f".uicolor(0.5) == :fuchsia.uicolor(0.5) == 0xff00ff.uicolor(0.5) # => UIColor.colorWithRed(1.0, green:1.0, blue:1.0, alpha:0.5)
|
|
517
|
-
# note: 0xf0f.uicolor == 0x000f0f.uicolor. There's no way to tell the difference
|
|
518
|
-
# at run time between those two Fixnum literals.
|
|
300
|
+
UITextView
|
|
301
|
+
------------
|
|
519
302
|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
"hello"._ # == "hello".localized
|
|
523
|
-
"hello".localized('Hello!', 'hello_table') # => ...("hello", value:'Hello!', table:'hello_table')
|
|
303
|
+
You MUST call the `off` methods, because these methods use `NSNotification`s,
|
|
304
|
+
and you must turn off listeners.
|
|
524
305
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
"my.plist".document # => NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true)[0].stringByAppendingPathComponent("my.plist")
|
|
528
|
-
"my.plist".cache # => NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, true)[0].stringByAppendingPathComponent("my.plist")
|
|
529
|
-
"my.plist".remove! # => NSFileManager.defaultManager.removeItemAtPath("my.plist".document, error: error) (returns error, if any occurred)
|
|
306
|
+
There are two aliases for each event. I prefer the present tense (jQuery-style `on :change`),
|
|
307
|
+
but UIKit prefers past simple (`UITextViewTextDidBeginEditingNotification`).
|
|
530
308
|
|
|
531
|
-
|
|
532
|
-
"my.plist".resource # => NSBundle.mainBundle.resourcePath.stringByAppendingPathComponent("my.plist")
|
|
533
|
-
# same, but get a URL instead - often used to display a static HTML page that is stored in resources
|
|
534
|
-
"index.html".resource_url # => NSBundle.mainBundle.URLForResource("index", withExtension:"html")
|
|
309
|
+
So these are all the same:
|
|
535
310
|
|
|
536
|
-
|
|
537
|
-
|
|
311
|
+
:editing_did_begin :begin
|
|
312
|
+
:editing_did_change :change
|
|
313
|
+
:editing_did_end :end
|
|
538
314
|
|
|
539
|
-
|
|
540
|
-
|
|
315
|
+
```ruby
|
|
316
|
+
text_view = UITextView.new
|
|
317
|
+
text_view.on :begin do
|
|
318
|
+
p 'wait for it...'
|
|
319
|
+
end
|
|
320
|
+
text_view.on :change do
|
|
321
|
+
p text_view.text
|
|
322
|
+
end
|
|
323
|
+
text_view.on :end do
|
|
324
|
+
p 'done!'
|
|
325
|
+
end
|
|
541
326
|
|
|
542
|
-
#
|
|
543
|
-
|
|
327
|
+
# later... like in `viewWillDisappear`. I'll use the alternative aliases here
|
|
328
|
+
text_view.off :editing_did_change, :editing_did_end, :editing_did_begin
|
|
544
329
|
```
|
|
545
330
|
|
|
546
|
-
|
|
547
|
-
|
|
331
|
+
Gestures
|
|
332
|
+
-----
|
|
548
333
|
|
|
549
|
-
|
|
550
|
-
|
|
334
|
+
> `require 'sugarcube-gestures'`
|
|
335
|
+
|
|
336
|
+
SugarCube's gesture support is very similar to BubbleWrap's, and it's entirely
|
|
337
|
+
possible that the two will be merged into one thing. But SugarCube is all about
|
|
338
|
+
extending base classes, whereas BubbleWrap tends to add *new* classes to do the
|
|
339
|
+
heavy lifting. Plus the options you pass to SugarCube are very different, and
|
|
340
|
+
the prefix is "on" instead of "when" (e.g. "on_pan" instead of "when_panned")
|
|
551
341
|
|
|
552
342
|
```ruby
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
when IndexPath[0]
|
|
556
|
-
when IndexPath[1, 0..5]
|
|
557
|
-
when IndexPath[1, 5..objects.length]
|
|
343
|
+
view.on_pan do |gesture|
|
|
344
|
+
location = gesture.view.locationInView(view)
|
|
558
345
|
end
|
|
559
|
-
|
|
346
|
+
|
|
347
|
+
# other gesture methods, with common options:
|
|
348
|
+
view.on_tap # use system defaults
|
|
349
|
+
view.on_tap(1) # number of taps
|
|
350
|
+
view.on_tap(taps: 1, fingers: 1) # number of taps and number of fingers
|
|
351
|
+
|
|
352
|
+
view.on_pinch # no options
|
|
353
|
+
view.on_rotate # no options
|
|
354
|
+
|
|
355
|
+
view.on_swipe # use system defaults
|
|
356
|
+
view.on_swipe :left
|
|
357
|
+
view.on_swipe(direction: :left, fingers: 1)
|
|
358
|
+
view.on_swipe(direction: UISwipeGestureRecognizerDirectionLeft, fingers: 1)
|
|
359
|
+
|
|
360
|
+
view.on_pan # use system defaults
|
|
361
|
+
view.on_pan(2) # minimum and maximum fingers required
|
|
362
|
+
view.on_pan(fingers: 2)
|
|
363
|
+
view.on_pan(min_fingers: 2, max_fingers: 3)
|
|
364
|
+
|
|
365
|
+
view.on_press # use system defaults
|
|
366
|
+
view.on_press(1.5) # duration
|
|
367
|
+
view.on_press(duration: 1.5, taps: 1, fingers: 1)
|
|
560
368
|
```
|
|
561
369
|
|
|
562
|
-
|
|
563
|
-
|
|
370
|
+
Notifications
|
|
371
|
+
-----
|
|
372
|
+
|
|
373
|
+
> `require 'sugarcube-notifications'`
|
|
564
374
|
|
|
565
|
-
|
|
375
|
+
Makes it easy to post a notification to some or all objects.
|
|
566
376
|
|
|
567
377
|
```ruby
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
:
|
|
573
|
-
:change.uicontrolevent # => UIControlEventValueChanged
|
|
574
|
-
:all.uicontrolevent # => UIControlEventAllEvents
|
|
575
|
-
:blue.uicolor # UIColor.blueColor
|
|
378
|
+
# this one is handy, I think:
|
|
379
|
+
MyNotification = "my notification"
|
|
380
|
+
MyNotification.post_notification # => NSNotificationCenter.defaultCenter.postNotificationName(MyNotification, object:nil)
|
|
381
|
+
MyNotification.post_notification(obj) # => NSNotificationCenter.defaultCenter.postNotificationName(MyNotification, object:obj)
|
|
382
|
+
MyNotification.post_notification(obj, user: 'dict') # => NSNotificationCenter.defaultCenter.postNotificationName(MyNotification, object:obj, userInfo:{user: 'dict'})
|
|
576
383
|
|
|
577
|
-
#
|
|
578
|
-
|
|
579
|
-
:
|
|
384
|
+
# you can access the userInfo dictionary directly from the notification
|
|
385
|
+
def notified(notification)
|
|
386
|
+
notification[:user] # => 'dict'
|
|
387
|
+
end
|
|
580
388
|
|
|
581
|
-
#
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
:bold.uifont # UIFont.boldSystemFontOfSize(UIFont.systemFontSize)
|
|
585
|
-
:bold.uifont(10) # UIFont.boldSystemFontOfSize(10)
|
|
586
|
-
:small.uifontsize # => UIFont.smallSystemFontSize
|
|
587
|
-
:small.uifont # => UIFont.systemFontOfSize(:small.uifontsize)
|
|
588
|
-
:bold.uifont(:small) # UIFont.boldSystemFontOfSize(:small.uifontsize)
|
|
589
|
-
:large.uiactivityindicatorstyle # :large, :white, :gray
|
|
590
|
-
:bar.uisegmentedstyle # :plain, :bordered, :bar, :bezeled
|
|
389
|
+
# very similar to add or remove an observer
|
|
390
|
+
MyNotification.add_observer(observer, :method_name)
|
|
391
|
+
MyNotification.add_observer(observer, :method_name, object)
|
|
591
392
|
|
|
592
|
-
#
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
:default.uitablecellstyle # or .uitableviewcellstyle
|
|
596
|
-
:disclosure.uitablecellaccessory # or .uitableviewcellaccessorytype
|
|
597
|
-
:blue.uitablecellselectionstyle # or .uitableviewcellselectionstyle
|
|
393
|
+
# remove the observer
|
|
394
|
+
MyNotification.remove_observer(observer)
|
|
395
|
+
MyNotification.remove_observer(observer, object)
|
|
598
396
|
```
|
|
599
397
|
|
|
600
398
|
UIImage
|
|
601
|
-
|
|
399
|
+
-----
|
|
602
400
|
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
401
|
+
Image Manipulation - VERY handy! Includes some quick maniputions on UIImage,
|
|
402
|
+
and adds an interface to chain together CIFilters. Plus, you can refer to
|
|
403
|
+
`cifilter.rb` to find out what filters are supported in iOS (all supported
|
|
404
|
+
filters get a class method in this file).
|
|
607
405
|
|
|
608
|
-
|
|
406
|
+
> `require 'sugarcube-image'`
|
|
609
407
|
|
|
408
|
+
###### UIImage additions
|
|
610
409
|
```ruby
|
|
611
410
|
image.scale_to [37, 37]
|
|
612
411
|
image.rounded # default: 5 pt radius
|
|
@@ -651,24 +450,107 @@ image.masked(mask_image)
|
|
|
651
450
|
image_ab = image_a << image_b
|
|
652
451
|
```
|
|
653
452
|
|
|
654
|
-
|
|
453
|
+
###### CIFilter additions
|
|
454
|
+
```ruby
|
|
455
|
+
# create a filter
|
|
456
|
+
gaussy = CIFilter.gaussian_blur(radius: 5)
|
|
457
|
+
gaussy = CIFilter.gaussian_blur(5) # this also works - you can find the arg order by looking in cifilter.rb
|
|
655
458
|
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
459
|
+
# apply a filter to a UIImage
|
|
460
|
+
new_image = image.apply_filter(gaussy).uiimage # apply_filter returns a CIImage, which is converted to UIImage
|
|
461
|
+
|
|
462
|
+
# apply a chain of filters using the `|` operator or `apply_filter`
|
|
463
|
+
darken = CIFilter.color_controls(saturation: 0, brightness: 0)
|
|
464
|
+
new_image = image.apply_filter(gaussy).apply_filter(darken).uiimage
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
If you include `sugarcube-pipes` you can use the `|` operator to chain filters:
|
|
659
468
|
|
|
660
469
|
```ruby
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
# => tall-568h@2x.png on iphone 5
|
|
470
|
+
# using the filters from above
|
|
471
|
+
new_image = image | gaussy | darken | UIImage
|
|
472
|
+
new_view = view | gaussy | darken | UIView
|
|
665
473
|
```
|
|
666
474
|
|
|
667
|
-
|
|
668
|
-
|
|
475
|
+
There are 91 filters available in iOS 6, I won't list them here, but check out
|
|
476
|
+
[the Apple documentation][core-image-filters] to read about them, and study
|
|
477
|
+
[cifilter.rb][].
|
|
478
|
+
|
|
479
|
+
[core-image-filters]: http://developer.apple.com/library/mac/#documentation/GraphicsImaging/Reference/CoreImageFilterReference/Reference/reference.html
|
|
480
|
+
[cifilter.rb]: https://github.com/colinta/sugarcube/blob/1.0/lib/sugarcube-image/cifilter.rb
|
|
481
|
+
[cifilter.rb-post-merge]: https://github.com/rubymotion/sugarcube/blob/master/lib/sugarcube-image/cifilter.rb
|
|
482
|
+
|
|
483
|
+
UIColor
|
|
484
|
+
-----
|
|
485
|
+
|
|
486
|
+
> `require 'sugarcube-color'`
|
|
487
|
+
|
|
488
|
+
Methods to merge or manipulate a color, or to get information about a color.
|
|
489
|
+
Works best on RGB colors, but HSB will work well, too. `UIColor`s based on
|
|
490
|
+
image patterns can't easily be inverted or mixed.
|
|
491
|
+
|
|
492
|
+
Any classes that have a well-defined "color" representation are given a
|
|
493
|
+
`uicolor` method, so it's easy to create a color from hex codes, css names,
|
|
494
|
+
or images (as patterns).
|
|
495
|
+
|
|
496
|
+
```ruby
|
|
497
|
+
:blue.uicolor # UIColor.blueColor
|
|
498
|
+
# uicolor() accepts an alpha value, too
|
|
499
|
+
:blue.uicolor(0.5)
|
|
500
|
+
|
|
501
|
+
# all CSS colors are supported (but no "grey" aliases, consistent with UIKit,
|
|
502
|
+
# which only provides "grayColor")
|
|
503
|
+
:firebrick.uicolor # => 0xb22222.uicolor
|
|
504
|
+
|
|
505
|
+
# RGB values, in the range 0..255.
|
|
506
|
+
[160, 210, 242].uicolor # => UIColor.colorWithRed(0.6274, green:0.8235, blue:0.9490, alpha:1.0)
|
|
507
|
+
[160, 210, 242].uicolor(0.5) # => UIColor.colorWithRed(0.6274, green:0.8235, blue:0.9490, alpha:0.5)
|
|
508
|
+
|
|
509
|
+
# create a UIColor from a hex value
|
|
510
|
+
0xffffff.uicolor # => UIColor.colorWithRed(1.0, green:1.0, blue:1.0, alpha:1.0)
|
|
511
|
+
0xffffff.uicolor(0.5) # => UIColor.colorWithRed(1.0, green:1.0, blue:1.0, alpha:0.5)
|
|
512
|
+
|
|
513
|
+
# works when using strings, too
|
|
514
|
+
"#fff".uicolor # => UIColor.whiteColor
|
|
515
|
+
"#ffffff".uicolor # => UIColor.whiteColor
|
|
516
|
+
"#ff00ff".uicolor == :fuchsia.uicolor == 0xff00ff.uicolor # => UIColor.colorWithRed(1.0, green:0.0, blue:1.0, alpha:1.0)
|
|
517
|
+
"#f0f".uicolor(0.5) == :fuchsia.uicolor(0.5) == 0xff00ff.uicolor(0.5) # => UIColor.colorWithRed(1.0, green:1.0, blue:1.0, alpha:0.5)
|
|
518
|
+
|
|
519
|
+
# note: 0xf0f.uicolor == 0x000f0f.uicolor. There's no way to tell the difference
|
|
520
|
+
# at run time between those two Fixnum literals.
|
|
521
|
+
|
|
522
|
+
# UIColor from image name, if the first character is not "#"
|
|
523
|
+
"pattern".uicolor == "pattern".uiimage.uicolor # => UIColor.colorWithPatternImage(UIImage.imageNamed("pattern"))
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
These methods are added onto the UIColor class:
|
|
527
|
+
|
|
528
|
+
```ruby
|
|
529
|
+
:red.uicolor.invert # => UIColor.cyanColor
|
|
530
|
+
:blue.uicolor.invert # => UIColor.yellowColor
|
|
531
|
+
:green.uicolor.invert # => UIColor.magentaColor
|
|
532
|
+
:red.uicolor + :blue.uicolor # => UIColor.purpleColor
|
|
533
|
+
:red.uicolor + :green.uicolor # => :olive.uicolor
|
|
534
|
+
# (I didn't know that until I tried it in the REPL, but it was pretty cool to
|
|
535
|
+
# see the UIColor#to_s method match that mixture to olive!)
|
|
536
|
+
|
|
537
|
+
# a more generic color mixing method (`+` delegates to this method):
|
|
538
|
+
:white.uicolor.mix_with(:black.uicolor, 0) # => :white
|
|
539
|
+
:white.uicolor.mix_with(:black.uicolor, 0.25) # => 0x404040.uicolor
|
|
540
|
+
:white.uicolor.mix_with(:black.uicolor, 0.5) # => :gray, same as :white.uicolor + :black.uicolor
|
|
541
|
+
:white.uicolor.mix_with(:black.uicolor, 0.75) # => 0xbfbfbf.uicolor
|
|
542
|
+
:white.uicolor.mix_with(:black.uicolor, 1) # => :black
|
|
543
|
+
|
|
544
|
+
# convert to CGColor
|
|
545
|
+
color.cgcolor
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
Factories
|
|
549
|
+
-----
|
|
550
|
+
|
|
551
|
+
> `require 'sugarcube-factories'`
|
|
669
552
|
|
|
670
|
-
UIAlertView
|
|
671
|
-
--------
|
|
553
|
+
###### UIAlertView
|
|
672
554
|
|
|
673
555
|
Accepts multiple buttons and handlers. In its simplest form, you can pass just
|
|
674
556
|
a title and block.
|
|
@@ -695,8 +577,7 @@ UIAlertView.alert "I mean, is this cool?", buttons: %w[No! Sure! Hmmmm],
|
|
|
695
577
|
success: proc { |pressed| self.proceed if pressed == "Sure!" }
|
|
696
578
|
```
|
|
697
579
|
|
|
698
|
-
UIActionSheet
|
|
699
|
-
--------
|
|
580
|
+
###### UIActionSheet
|
|
700
581
|
|
|
701
582
|
This is very similar to `UIAlertView.alert`, but instead of `cancel` and
|
|
702
583
|
`success` handlers, you can have `cancel, success, and destructive` handlers,
|
|
@@ -725,352 +606,220 @@ UIActionSheet.alert 'I mean, is this cool?', buttons: ['Nah', 'With fire!', 'Sur
|
|
|
725
606
|
success: proc { |pressed| self.proceed if pressed == 'Sure' }
|
|
726
607
|
```
|
|
727
608
|
|
|
728
|
-
|
|
729
|
-
---------
|
|
730
|
-
|
|
731
|
-
Methods to merge or manipulate a color, or to get information about a color.
|
|
732
|
-
Works best on RGB colors, but HSB will work well, too. `UIColor`s based on
|
|
733
|
-
image patterns can't easily be inverted or mixed.
|
|
734
|
-
|
|
735
|
-
```ruby
|
|
736
|
-
:red.uicolor.invert # => UIColor.cyanColor
|
|
737
|
-
:blue.uicolor.invert # => UIColor.yellowColor
|
|
738
|
-
:green.uicolor.invert # => UIColor.magentaColor
|
|
739
|
-
:red.uicolor + :blue.uicolor # => UIColor.purpleColor
|
|
740
|
-
:red.uicolor + :green.uicolor # => :olive.uicolor
|
|
741
|
-
# (I didn't know that until I tried it in the REPL, but it was pretty cool to
|
|
742
|
-
# see the UIColor#to_s method match that mixture to olive!)
|
|
743
|
-
|
|
744
|
-
# a more generic color mixing method (`+` delegates to this method):
|
|
745
|
-
:white.uicolor.mix_with(:black.uicolor, 0) # => :white
|
|
746
|
-
:white.uicolor.mix_with(:black.uicolor, 0.25) # => 0x404040.uicolor
|
|
747
|
-
:white.uicolor.mix_with(:black.uicolor, 0.5) # => :gray, same as :white + :black
|
|
748
|
-
:white.uicolor.mix_with(:black.uicolor, 0.75) # => 0xbfbfbf.uicolor
|
|
749
|
-
:white.uicolor.mix_with(:black.uicolor, 1) # => :black
|
|
750
|
-
```
|
|
751
|
-
|
|
752
|
-
UIView
|
|
753
|
-
--------
|
|
754
|
-
|
|
755
|
-
```ruby
|
|
756
|
-
UIView.first_responder # => returns the first responder, starting at UIApplication.sharedApplication.keyWindow
|
|
757
|
-
my_view.first_responder # => also returns the first responder, but starts looking in my_view
|
|
758
|
-
my_view.controller # => returns the UIViewController that this view belongs to
|
|
759
|
-
self.view << subview # => self.view.addSubview(subview)
|
|
760
|
-
self.view.show # => self.hidden = false
|
|
761
|
-
self.view.hide # => self.hidden = true
|
|
762
|
-
|
|
763
|
-
# convert to UIImage. retina-ready.
|
|
764
|
-
my_view.uiimage
|
|
765
|
-
# that will use the `bounds` property to size the image. but if you want a
|
|
766
|
-
# screen shot of the contents of a scroll view, pass in `true` or `:all` to this
|
|
767
|
-
# method.
|
|
768
|
-
my_scroll_view.uiimage(:all)
|
|
769
|
-
```
|
|
770
|
-
|
|
771
|
-
When defining a UIView subclass, you often have attributes that affect your
|
|
772
|
-
`drawRect` method (99% of the time, ALL the attributes affect drawing, right?).
|
|
773
|
-
So SugarCube adds a `attr_updates` method, which creates an attribute identical
|
|
774
|
-
to `attr_accessor` but the setter calls setNeedsDisplay if the new value != the
|
|
775
|
-
old value.
|
|
776
|
-
|
|
609
|
+
###### UIButton
|
|
777
610
|
```ruby
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
def drawRect(rect)
|
|
782
|
-
# ...
|
|
783
|
-
end
|
|
784
|
-
end
|
|
611
|
+
UIButton.buttonWithType(:custom.uibuttontype)
|
|
612
|
+
# =>
|
|
613
|
+
UIButton.custom
|
|
785
614
|
|
|
786
|
-
|
|
787
|
-
|
|
615
|
+
UIButton.custom => UIButton.buttonWithType(:custom.uibuttontype)
|
|
616
|
+
UIButton.rounded => UIButton.buttonWithType(:rounded.uibuttontype)
|
|
617
|
+
UIButton.rounded_rect => UIButton.buttonWithType(:rounded_rect.uibuttontype)
|
|
618
|
+
UIButton.detail => UIButton.buttonWithType(:detail.uibuttontype)
|
|
619
|
+
UIButton.detail_disclosure => UIButton.buttonWithType(:detail_disclosure.uibuttontype)
|
|
620
|
+
UIButton.info => UIButton.buttonWithType(:info.uibuttontype)
|
|
621
|
+
UIButton.info_light => UIButton.buttonWithType(:info_light.uibuttontype)
|
|
622
|
+
UIButton.info_dark => UIButton.buttonWithType(:info_dark.uibuttontype)
|
|
623
|
+
UIButton.contact => UIButton.buttonWithType(:contact.uibuttontype)
|
|
624
|
+
UIButton.contact_add => UIButton.buttonWithType(:contact_add.uibuttontype)
|
|
788
625
|
```
|
|
789
626
|
|
|
790
|
-
######
|
|
627
|
+
###### UITableView
|
|
791
628
|
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
provides it to all its completion handlers).
|
|
629
|
+
Default frame is `[[0, 0], [0, 0]]`, but most containers will resize it to be
|
|
630
|
+
the correct size. But heads up, it *was* `[[0, 0], [320, 480]]` (until
|
|
631
|
+
the iphone 5 / 4-inch retina came out).
|
|
796
632
|
|
|
797
633
|
```ruby
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
#
|
|
802
|
-
|
|
803
|
-
view.removeFromSuperview
|
|
804
|
-
end
|
|
805
|
-
|
|
806
|
-
# and the completed argument
|
|
807
|
-
view.fade_out do |completed|
|
|
808
|
-
view.removeFromSuperview
|
|
809
|
-
end
|
|
810
|
-
|
|
811
|
-
# fade_out options
|
|
812
|
-
view.fade_out(duration: 0.5,
|
|
813
|
-
delay: 0,
|
|
814
|
-
options: UIViewAnimationOptionCurveLinear,
|
|
815
|
-
opacity: 0.5) do
|
|
816
|
-
view.removeFromSuperview
|
|
817
|
-
end
|
|
634
|
+
UITableView.alloc.initWithFrame([[0, 0], [0, 0]], style: :plain.uitableviewstyle)
|
|
635
|
+
UITableView.alloc.initWithFrame([[0, 0], [320, 480]], style: :plain.uitableviewstyle)
|
|
636
|
+
UITableView.alloc.initWithFrame([[0, 0], [320, 568]], style: :plain.uitableviewstyle)
|
|
637
|
+
# custom frame:
|
|
638
|
+
UITableView.alloc.initWithFrame([[0, 0], [320, 400]], style: :grouped.uitableviewstyle)
|
|
818
639
|
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
view.slide :left # slides the entire view left, right, up, or down. The
|
|
827
|
-
# default amount is the width of the view being moved, but
|
|
828
|
-
# you can override
|
|
829
|
-
view.slide :left, 320
|
|
830
|
-
|
|
831
|
-
view.shake # shakes the view.
|
|
832
|
-
# options w/ default values:
|
|
833
|
-
shake offset: 8, # move 8 px left, and 8 px right
|
|
834
|
-
repeat: 3, # three times
|
|
835
|
-
duration: 0.3, # for a total of 0.3 seconds
|
|
836
|
-
keypath: 'transform.translate.x'
|
|
837
|
-
|
|
838
|
-
# vigorous nodding - modifying transform.translation.y:
|
|
839
|
-
view.shake offset: 20, repeat: 10, duration: 5, keypath: 'transform.translation.y'
|
|
840
|
-
# an adorable wiggle - modifying transform.rotation:
|
|
841
|
-
view.shake offset: 0.1, repeat: 2, duration: 0.5, keypath: 'transform.rotation'
|
|
842
|
-
|
|
843
|
-
# this was pulled off warrenm's AHAlertView project. I thought the effect was
|
|
844
|
-
# awesome, and deserved more attention!
|
|
845
|
-
# https://github.com/warrenm/AHAlertView
|
|
846
|
-
view.tumble # the view will fall and rotate - a good 'cancel button effect'
|
|
640
|
+
# =>
|
|
641
|
+
UITableView.plain
|
|
642
|
+
UITableView.plain([[0, 0], [320, 480]])
|
|
643
|
+
UITableView.plain([[0, 0], [320, 568]])
|
|
644
|
+
# custom frame:
|
|
645
|
+
UITableView.grouped([[0, 0], [320, 400]])
|
|
847
646
|
```
|
|
848
647
|
|
|
849
|
-
|
|
850
|
-
current" position (`UIViewAnimationOptionBeginFromCurrentState`). To disable
|
|
851
|
-
that, you can either assign `options:` to something else, or you can disable
|
|
648
|
+
###### UITableViewCell
|
|
852
649
|
|
|
853
650
|
```ruby
|
|
854
|
-
#
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
651
|
+
# factory methods, named for the cell style. cell identifier is required.
|
|
652
|
+
UITableViewCell.default('cell_identifier')
|
|
653
|
+
UITableViewCell.value1('cell_identifier')
|
|
654
|
+
UITableViewCell.value2('cell_identifier')
|
|
655
|
+
UITableViewCell.subtitle('cell_identifier')
|
|
859
656
|
|
|
860
|
-
|
|
861
|
-
|
|
657
|
+
# you can options for the common settings
|
|
658
|
+
cell = UITableViewCell.default('cell_identifier',
|
|
659
|
+
accessory: :disclosure,
|
|
660
|
+
selection: :blue,
|
|
661
|
+
text: 'text',
|
|
662
|
+
image: 'icon', # coerced into a UIImage
|
|
663
|
+
)
|
|
862
664
|
```
|
|
863
665
|
|
|
864
|
-
|
|
666
|
+
###### UISegmentedControl
|
|
865
667
|
|
|
866
668
|
```ruby
|
|
867
|
-
|
|
868
|
-
|
|
669
|
+
control = UISegmentedControl.alloc.initItems(["one", "ah-two-whoo", "thr-r-r-ree"])
|
|
670
|
+
control.segmentedControlStyle = :bar.uisegmentedstyle
|
|
869
671
|
|
|
870
|
-
|
|
871
|
-
assign them direcly to `options:` if there are options you need that are not
|
|
872
|
-
listed here.
|
|
672
|
+
# =>
|
|
873
673
|
|
|
874
|
-
|
|
875
|
-
|
|
674
|
+
UISegmentedControl.bar(["one", "ah-two-whoo", "thr-r-r-ree"])
|
|
675
|
+
# plain, bordered, and bezeled are the other types
|
|
876
676
|
```
|
|
877
677
|
|
|
878
|
-
|
|
879
|
-
animation sequence.
|
|
678
|
+
###### UIActivityViewIndicator
|
|
880
679
|
|
|
881
680
|
```ruby
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
view.slide(:down, 20) do
|
|
886
|
-
view.fade_out
|
|
887
|
-
end
|
|
888
|
-
end
|
|
889
|
-
end
|
|
890
|
-
end
|
|
891
|
-
```
|
|
681
|
+
UIActivityIndicatorView.alloc.initWithActivityIndicatorStyle(UIActivityIndicatorViewStyleWhite)
|
|
682
|
+
UIActivityIndicatorView.alloc.initWithActivityIndicatorStyle(UIActivityIndicatorViewStyleWhiteLarge)
|
|
683
|
+
UIActivityIndicatorView.alloc.initWithActivityIndicatorStyle(UIActivityIndicatorViewStyleGray)
|
|
892
684
|
|
|
893
|
-
|
|
685
|
+
# =>
|
|
894
686
|
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
}.and_then {
|
|
899
|
-
view.slide(:up, 20)
|
|
900
|
-
}.and_then {
|
|
901
|
-
view.slide(:right, 20)
|
|
902
|
-
}.and_then {
|
|
903
|
-
view.slide(:down, 20)
|
|
904
|
-
}.and_then {
|
|
905
|
-
view.fade_out
|
|
906
|
-
}.start
|
|
687
|
+
UIActivityIndicatorView.white
|
|
688
|
+
UIActivityIndicatorView.large
|
|
689
|
+
UIActivityIndicatorView.gray
|
|
907
690
|
```
|
|
908
691
|
|
|
909
|
-
|
|
910
|
-
`rotate`) will be setup to run *immediately* instead of in a
|
|
911
|
-
`UIView#animateWithDuration(...)` block. You can also do multiple animations
|
|
912
|
-
within that block, as long as no two animations affect the same property:
|
|
913
|
-
|
|
914
|
-
```ruby
|
|
915
|
-
UIView.animation_chain {
|
|
916
|
-
view.slide(:left, 20)
|
|
917
|
-
view.rotate(90.degrees)
|
|
918
|
-
}.and_then {
|
|
919
|
-
view.slide(:up, 20)
|
|
920
|
-
view.rotate(90.degrees)
|
|
921
|
-
}.and_then {
|
|
922
|
-
view.slide(:right, 20)
|
|
923
|
-
view.rotate(90.degrees)
|
|
924
|
-
}.and_then {
|
|
925
|
-
view.slide(:down, 20)
|
|
926
|
-
view.rotate(90.degrees)
|
|
927
|
-
}.and_then {
|
|
928
|
-
view.fade_out
|
|
929
|
-
view.rotate_to(0.degrees)
|
|
930
|
-
}.start
|
|
931
|
-
```
|
|
692
|
+
###### UIBarButtonItem
|
|
932
693
|
|
|
933
|
-
|
|
694
|
+
These factory methods accept a block, which will get wired up as a
|
|
695
|
+
target/action.
|
|
934
696
|
|
|
935
697
|
```ruby
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
chain.
|
|
698
|
+
# Get an instance containing the specified system item.
|
|
699
|
+
UIBarButtonItem.done do
|
|
700
|
+
self.dismissViewControllerAnimated true, completion:nil
|
|
701
|
+
end
|
|
702
|
+
# =>
|
|
703
|
+
UIBarButtonItem.alloc.initWithBarButtonSystemItem(:done.uibarbuttonitem, target:self, action:"action:")
|
|
704
|
+
# with 'action' defined as:
|
|
705
|
+
def action(sender)
|
|
706
|
+
self.dismissViewControllerAnimated true, completion:nil
|
|
707
|
+
end
|
|
947
708
|
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
}.
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
# if you're impatient
|
|
958
|
-
chain.abort
|
|
959
|
-
# will stop the animation at the end of whatever block it is in, so it could be
|
|
960
|
-
# in a strange position, depending on where in the chain it is. Better to call
|
|
961
|
-
# `stop`
|
|
709
|
+
# the method names are 1::1 with the uibarbuttonitem constants in symbol.rb
|
|
710
|
+
UIBarButtonItem.cancel { ... } => UIBarButtonItem.alloc.initWithBarButtonSystemItem(:cancel.uibarbuttonitem, target:self, action:"action:")
|
|
711
|
+
UIBarButtonItem.edit { ... } => UIBarButtonItem.alloc.initWithBarButtonSystemItem(:edit.uibarbuttonitem, target:self, action:"action:")
|
|
712
|
+
UIBarButtonItem.save { ... } => UIBarButtonItem.alloc.initWithBarButtonSystemItem(:save.uibarbuttonitem, target:self, action:"action:")
|
|
713
|
+
.
|
|
714
|
+
.
|
|
715
|
+
.
|
|
716
|
+
UIBarButtonItem.page_curl { ... } => UIBarButtonItem.alloc.initWithBarButtonSystemItem(:page_curl.uibarbuttonitem, target:self, action:"action:")
|
|
962
717
|
```
|
|
963
718
|
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
###### UIButton
|
|
719
|
+
For custom `UIBarButtonItem`s, you can use the `titled` and `imaged` methods:
|
|
967
720
|
|
|
968
721
|
```ruby
|
|
969
|
-
|
|
722
|
+
# Create a UIBarButtonItem, specifying the title
|
|
723
|
+
UIBarButtonItem.titled('Close') do
|
|
724
|
+
self.dismissViewControllerAnimated(true, completion:nil)
|
|
725
|
+
end
|
|
970
726
|
# =>
|
|
971
|
-
|
|
727
|
+
UIBarButtonItem.alloc.initWithTitle('Close', style: :bordered.uibarbuttonstyle, target:self, action:"action:")
|
|
728
|
+
def action(sender)
|
|
729
|
+
self.dismissViewControllerAnimated(true, completion:nil)
|
|
730
|
+
end
|
|
972
731
|
|
|
973
|
-
UIButton.custom => UIButton.buttonWithType(:custom.uibuttontype)
|
|
974
|
-
UIButton.rounded => UIButton.buttonWithType(:rounded.uibuttontype)
|
|
975
|
-
UIButton.rounded_rect => UIButton.buttonWithType(:rounded_rect.uibuttontype)
|
|
976
|
-
UIButton.detail => UIButton.buttonWithType(:detail.uibuttontype)
|
|
977
|
-
UIButton.detail_disclosure => UIButton.buttonWithType(:detail_disclosure.uibuttontype)
|
|
978
|
-
UIButton.info => UIButton.buttonWithType(:info.uibuttontype)
|
|
979
|
-
UIButton.info_light => UIButton.buttonWithType(:info_light.uibuttontype)
|
|
980
|
-
UIButton.info_dark => UIButton.buttonWithType(:info_dark.uibuttontype)
|
|
981
|
-
UIButton.contact => UIButton.buttonWithType(:contact.uibuttontype)
|
|
982
|
-
UIButton.contact_add => UIButton.buttonWithType(:contact_add.uibuttontype)
|
|
983
|
-
```
|
|
984
732
|
|
|
985
|
-
|
|
733
|
+
# You can also specify the style.
|
|
734
|
+
UIBarButtonItem.titled('Close', :plain) do # :plain, :bordered, :done
|
|
735
|
+
# ...
|
|
736
|
+
end
|
|
986
737
|
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
738
|
+
# Or specify the image instead
|
|
739
|
+
UIBarButtonItem.imaged('close_icon') do # 'close_icon' will be coerced into a UIImage
|
|
740
|
+
# ...
|
|
741
|
+
end
|
|
742
|
+
# =>
|
|
743
|
+
UIBarButtonItem.alloc.initWithImage('Close'.uiimage, style: :bordered.uibarbuttonstyle, ...)
|
|
990
744
|
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
# custom frame:
|
|
996
|
-
UITableView.alloc.initWithFrame([[0, 0], [320, 400]], style: :grouped.uitableviewstyle)
|
|
745
|
+
# And, like `titled`, specify the style
|
|
746
|
+
UIBarButtonItem.imaged('close'.uiimage, :done) do
|
|
747
|
+
# ...
|
|
748
|
+
end
|
|
997
749
|
|
|
998
|
-
#
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
#
|
|
1003
|
-
|
|
750
|
+
# If you provide two images, they will be used as the portrait and landscape images
|
|
751
|
+
UIBarButtonItem.imaged(['portrait'.uiimage, 'landscape'.uiimage) do
|
|
752
|
+
# ...
|
|
753
|
+
end
|
|
754
|
+
# =>
|
|
755
|
+
UIBarButtonItem.alloc.initWithImage('portrait'.uiimage, landscapeImagePhone:'landscape'.uiimage, style: :bordered.uibarbuttonstyle, target:self, action:"action:")
|
|
1004
756
|
```
|
|
1005
757
|
|
|
1006
|
-
|
|
1007
|
-
|
|
758
|
+
Example Usage:
|
|
1008
759
|
```ruby
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
# you can options for the common settings
|
|
1016
|
-
cell = UITableViewCell.default('cell_identifier',
|
|
1017
|
-
accessory: :disclosure,
|
|
1018
|
-
selection: :blue,
|
|
1019
|
-
text: 'text',
|
|
1020
|
-
image: 'icon', # coerced into a UIImage
|
|
1021
|
-
)
|
|
760
|
+
toolbar = UIToolbar.new
|
|
761
|
+
toolbar.items = [
|
|
762
|
+
@image_picker_button = UIBarButtonItem.camera { presentImagePickerController(self) },
|
|
763
|
+
UIBarButtonItem.flexiblespace,
|
|
764
|
+
@saveButton = UIBarButtonItem.save { save_photo(self) }
|
|
765
|
+
]
|
|
1022
766
|
```
|
|
1023
767
|
|
|
1024
|
-
######
|
|
1025
|
-
|
|
768
|
+
###### NSError
|
|
1026
769
|
```ruby
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
# =>
|
|
1031
|
-
|
|
1032
|
-
UISegmentedControl.bar(["one", "ah-two-whoo", "thr-r-r-ree"])
|
|
770
|
+
# usually, NSError.new doesn't work, because the only initializer for NSError
|
|
771
|
+
# needs more arguments. This method passes some defaults in.
|
|
772
|
+
NSError.new('message')
|
|
773
|
+
# same as =>
|
|
774
|
+
NSError.new('message', domain: 'Error', code: 0, userInfo: {})
|
|
1033
775
|
```
|
|
1034
776
|
|
|
1035
|
-
|
|
777
|
+
Animations ([wiki][Animations Wiki])
|
|
778
|
+
-----
|
|
1036
779
|
|
|
1037
|
-
|
|
1038
|
-
UIActivityIndicatorView.alloc.initWithActivityIndicatorStyle(:white.uiactivityindicatorstyle)
|
|
1039
|
-
UIActivityIndicatorView.alloc.initWithActivityIndicatorStyle(:large.uiactivityindicatorstyle)
|
|
1040
|
-
UIActivityIndicatorView.alloc.initWithActivityIndicatorStyle(:gray.uiactivityindicatorstyle)
|
|
780
|
+
> `require 'sugarcube-animations'`
|
|
1041
781
|
|
|
1042
|
-
|
|
782
|
+
Careful, once you start using these helpers, you'll never go back.
|
|
1043
783
|
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
784
|
+
```ruby
|
|
785
|
+
view.fade_out
|
|
786
|
+
view.slide :left, 100
|
|
787
|
+
view.rotate_to 180.degrees
|
|
788
|
+
view.shake # great for showing invalid form elements
|
|
789
|
+
view.tumble # great way to dismiss an alert-like-view
|
|
1047
790
|
```
|
|
1048
791
|
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
verbs and SugarCube symbols.
|
|
792
|
+
These helpers all delegate to the `UIView.animate` method, which accepts all the
|
|
793
|
+
options that `UIView.animateWithDuration(delay:options:animations:completion:)`
|
|
794
|
+
accepts, but they are optional, and they will play nicely inside an animation
|
|
795
|
+
chain.
|
|
1054
796
|
|
|
1055
797
|
```ruby
|
|
1056
|
-
|
|
798
|
+
UIView.animate do
|
|
799
|
+
view.alpha = 0
|
|
800
|
+
end
|
|
801
|
+
```
|
|
1057
802
|
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
puts event.inspect
|
|
1061
|
-
# my_code...
|
|
1062
|
-
}
|
|
803
|
+
The [wiki] page documents all the different animation methods, and documents
|
|
804
|
+
animation chaining, which looks like this:
|
|
1063
805
|
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
806
|
+
```ruby
|
|
807
|
+
# fade out and slide left, then fade back in while returning to original position
|
|
808
|
+
UIView.animation_chain do
|
|
809
|
+
view.fade_out
|
|
810
|
+
view.slide :left
|
|
811
|
+
end.and_then do
|
|
812
|
+
view.fade_in
|
|
813
|
+
view.slide :right
|
|
814
|
+
end.start
|
|
1067
815
|
```
|
|
1068
816
|
|
|
1069
|
-
|
|
1070
|
-
|
|
817
|
+
[Animations Wiki]: https://github.com/rubymotion/sugarcube/wiki/Animations
|
|
818
|
+
|
|
819
|
+
Modal
|
|
820
|
+
-----
|
|
1071
821
|
|
|
1072
|
-
|
|
1073
|
-
------------------
|
|
822
|
+
> `require 'sugarcube-modal'`
|
|
1074
823
|
|
|
1075
824
|
It is nice that *any* `UIViewController` can present a modal, but if you have
|
|
1076
825
|
tabs or navs or crap in the way, this is actually *NOT* what you want. You
|
|
@@ -1080,7 +829,8 @@ And since this is a property on `UIWindow`, which is more-or-less a constant, we
|
|
|
1080
829
|
can make this the easiest to do!
|
|
1081
830
|
|
|
1082
831
|
```ruby
|
|
1083
|
-
include SugarCube::Modal
|
|
832
|
+
include SugarCube::Modal # make these methods available globally
|
|
833
|
+
|
|
1084
834
|
view_ctlr = EditSomethingViewController.new
|
|
1085
835
|
present_modal(view_ctlr)
|
|
1086
836
|
# ...later, when all is well...
|
|
@@ -1101,247 +851,331 @@ re-defined on `UIViewController` for this purpose:
|
|
|
1101
851
|
controller.present_modal(other_controller) { puts "presented" }
|
|
1102
852
|
```
|
|
1103
853
|
|
|
1104
|
-
|
|
1105
|
-
|
|
854
|
+
Numbers
|
|
855
|
+
-----
|
|
1106
856
|
|
|
1107
|
-
|
|
857
|
+
> `require 'sugarcube-numbers'`
|
|
1108
858
|
|
|
1109
|
-
|
|
859
|
+
### Converting input
|
|
1110
860
|
|
|
1111
|
-
`
|
|
1112
|
-
`:root` which does what you might expect
|
|
861
|
+
Uses `NSNumberFormatter` to try and parse a human-readable number string.
|
|
1113
862
|
|
|
1114
863
|
```ruby
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
nav_ctlr << last_ctlr
|
|
1121
|
-
nav_ctlr.pop # => pops to another_ctlr, because it's next on the stack
|
|
1122
|
-
nav_ctlr.pop new_ctlr # => pops to new_ctlr
|
|
1123
|
-
nav_ctlr.pop :root # => pops to root_ctlr, because it's on the bottom
|
|
864
|
+
if input.nan?
|
|
865
|
+
UIAlertView.alert('not a number!')
|
|
866
|
+
else
|
|
867
|
+
number = input.to_number
|
|
868
|
+
end
|
|
1124
869
|
```
|
|
1125
870
|
|
|
1126
|
-
|
|
1127
|
-
------------------------
|
|
871
|
+
### Pretty print numbers
|
|
1128
872
|
|
|
1129
|
-
|
|
1130
|
-
you will, too... Usually a `UITabBarController` has a static number of tabs,
|
|
1131
|
-
but in my case, I needed to be able to add one later, when a certain condition
|
|
1132
|
-
was met.
|
|
873
|
+
Use NSNumberFormatter to easily format a number in the current locale
|
|
1133
874
|
|
|
1134
875
|
```ruby
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
876
|
+
10000.string_with_style # => "10,000"
|
|
877
|
+
10000.string_with_style(NSNumberFormatterCurrencyStyle) # => "$10,000.00"
|
|
878
|
+
# will convert symbol-constants using the sugarcube-constants package, if it is available
|
|
879
|
+
10000.string_with_style(:currency) # => "$10,000.00"
|
|
880
|
+
```
|
|
1138
881
|
|
|
1139
|
-
|
|
882
|
+
### Percent
|
|
1140
883
|
|
|
1141
|
-
|
|
884
|
+
```ruby
|
|
885
|
+
100.0.percent # => 1.00
|
|
886
|
+
55.0.percent # => 0.55
|
|
1142
887
|
```
|
|
1143
888
|
|
|
1144
|
-
|
|
1145
|
-
------------
|
|
889
|
+
### Ordinals
|
|
1146
890
|
|
|
1147
|
-
|
|
1148
|
-
|
|
891
|
+
```ruby
|
|
892
|
+
# some number-to-string stuff
|
|
893
|
+
1.nth # => 'st'
|
|
894
|
+
2.nth # => 'nd'
|
|
895
|
+
3.nth # => 'rd'
|
|
896
|
+
4.nth # => 'th'
|
|
897
|
+
11.nth # => 'th'
|
|
898
|
+
13.nth # => 'th'
|
|
899
|
+
21.nth # => 'st'
|
|
900
|
+
23.nth # => 'rd'
|
|
901
|
+
```
|
|
1149
902
|
|
|
1150
|
-
|
|
1151
|
-
but UIKit prefers past simple (`UITextViewTextDidBeginEditingNotification`).
|
|
903
|
+
### Angles
|
|
1152
904
|
|
|
1153
|
-
|
|
905
|
+
Since you always want to work in radians, calling `10.degrees` returns 10°, *in
|
|
906
|
+
radians*. You can convert back to degrees using `to_degrees`. Lastly, you can
|
|
907
|
+
specify a multiple of π as a number:
|
|
1154
908
|
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
909
|
+
```ruby
|
|
910
|
+
10.degrees # => π / 18
|
|
911
|
+
45.degrees # => π / 4
|
|
912
|
+
3.14159.to_degrees # => approx 180
|
|
913
|
+
2.pi # => 6.28318...
|
|
914
|
+
```
|
|
915
|
+
|
|
916
|
+
### Distances
|
|
917
|
+
|
|
918
|
+
If you thought conversion from degrees to radians looks weird, you'll hate
|
|
919
|
+
conversion from meters to miles:
|
|
1158
920
|
|
|
1159
921
|
```ruby
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
p text_view.text
|
|
1166
|
-
end
|
|
1167
|
-
text_view.on :editing_did_end do
|
|
1168
|
-
p 'done!'
|
|
1169
|
-
end
|
|
922
|
+
distance = 1500 # this is in meters. why? because all the methods that return
|
|
923
|
+
# a "distance" return it in meters
|
|
924
|
+
distance = 2.miles # => 3218.688, that's how many meters are in 2 miles
|
|
925
|
+
1500.in_miles # converts meters to miles => 0.932056427001953
|
|
926
|
+
```
|
|
1170
927
|
|
|
1171
|
-
|
|
1172
|
-
|
|
928
|
+
### Sizes
|
|
929
|
+
|
|
930
|
+
Similar conversion methods for hard disk sizes. Uses the "mebi-byte" concepts,
|
|
931
|
+
e.g. 1024 bytes in a kilobyte.
|
|
932
|
+
|
|
933
|
+
```ruby
|
|
934
|
+
1.byte # => 1
|
|
935
|
+
1.kilobyte # => 1024
|
|
936
|
+
1.megabyte # => 1048576
|
|
937
|
+
1.gigabyte # => 1073741824
|
|
938
|
+
1.terabyte # => 1099511627776
|
|
939
|
+
1.petabyte # => 1125899906842624
|
|
940
|
+
1.exabyte # => 1152921504606846976
|
|
941
|
+
|
|
942
|
+
1.megabyte.in_kilobytes # => 1024
|
|
943
|
+
```
|
|
944
|
+
|
|
945
|
+
AttributedString
|
|
946
|
+
-----
|
|
947
|
+
|
|
948
|
+
> `require 'sugarcube-attributedstring'`
|
|
949
|
+
|
|
950
|
+
These are pretty fun! Check out [nsattributedstring_spec.rb][] for all the
|
|
951
|
+
supported attributes (in theory they are all supported, but there's weird
|
|
952
|
+
issues with missing constants).
|
|
953
|
+
|
|
954
|
+
[nsattributedstring.rb]: https://github.com/rubymotion/sugarcube/blob/master/lib/sugarcube-attributedstring/nsattributedstring.rb
|
|
955
|
+
|
|
956
|
+
```ruby
|
|
957
|
+
'test'.nsattributedstring({}) #=> NSAttributedString.alloc.initWithString('test', attributes:{})
|
|
958
|
+
'test'.attrd # => alias for `nsattributedstring`
|
|
959
|
+
'test'.bold # => NSAttributedString.alloc.initWithString('test', attributes:{NSFontAttributeName => :bold.uifont})
|
|
960
|
+
'test'.italic # => NSAttributedString.alloc.initWithString('test', attributes:{NSFontAttributeName => :italic.uifont})
|
|
961
|
+
'test'.underline # => NSAttributedString.alloc.initWithString('test', attributes:{NSUnderlineStyleAttributeName => NSUnderlineStyleSingle})
|
|
962
|
+
|
|
963
|
+
# you can chain 'em, too.
|
|
964
|
+
'test'.bold.underline
|
|
965
|
+
# If you look up NSAttributedString Application Kit Additions, you can see all
|
|
966
|
+
# the constants. Each of those has a method on NSAttributedString.
|
|
967
|
+
|
|
968
|
+
# you can add 'em, but the FIRST one MUST be an NSAttributedString
|
|
969
|
+
'test'.attrd + '-ing'.italic
|
|
970
|
+
|
|
971
|
+
# And there's where it gets FUN:
|
|
972
|
+
('This'.italic + ' is going to be ' + 'FUN'.bold).underline
|
|
973
|
+
```
|
|
974
|
+
|
|
975
|
+
And you can easily turn an attributed string into a label, if you include the
|
|
976
|
+
`sugarcube-uikit` package.
|
|
977
|
+
|
|
978
|
+
```ruby
|
|
979
|
+
view << (("We just met\n".attrd +
|
|
980
|
+
"and this is " + "CRAZY".italic + "\n"
|
|
981
|
+
"But here's my " + "id_rsa.pub".monospace + " file,\n" +
|
|
982
|
+
"so give me SSH access.").uilabel
|
|
1173
983
|
```
|
|
1174
984
|
|
|
1175
|
-
|
|
1176
|
-
|
|
985
|
+
568
|
|
986
|
+
-----
|
|
987
|
+
|
|
988
|
+
> `require 'sugarcube-568'`
|
|
1177
989
|
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
990
|
+
If you `require 'sugarcube-568'` in your Rakefile, you can use
|
|
991
|
+
`UIImage.imageNamed(name)` or `name.uiimage` to load images that are specific to
|
|
992
|
+
the 4" iphone.
|
|
1181
993
|
|
|
1182
|
-
The font size changes instead of the frame size.
|
|
1183
994
|
```ruby
|
|
1184
|
-
#
|
|
1185
|
-
|
|
1186
|
-
|
|
995
|
+
'tall'.uiimage # => UIImage.imageNamed('tall')
|
|
996
|
+
# => tall.png on iphone 3g
|
|
997
|
+
# => tall@2x.png on iphone 4
|
|
998
|
+
# => tall-568h@2x.png on iphone 5
|
|
1187
999
|
```
|
|
1188
1000
|
|
|
1001
|
+
This code is ported from <https://github.com/gaj/imageNamed568>, which I had
|
|
1002
|
+
some problems with on RubyMotion (it worked, but not *always*. Very strange).
|
|
1003
|
+
|
|
1004
|
+
Files
|
|
1005
|
+
-----
|
|
1189
1006
|
|
|
1007
|
+
Methods to find document files, resource files, cache files, and to access
|
|
1008
|
+
entries out of the Info.plist file.
|
|
1190
1009
|
|
|
1191
|
-
|
|
1192
|
-
----------------------
|
|
1010
|
+
> `require 'sugarcube-files'`
|
|
1193
1011
|
|
|
1194
1012
|
```ruby
|
|
1195
|
-
#
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
# =>
|
|
1200
|
-
UIBarButtonItem.alloc.initWithBarButtonSystemItem(:done.uibarbuttonitem, target:self, action:"action:")
|
|
1201
|
-
# with 'action' defined as:
|
|
1202
|
-
def action(sender)
|
|
1203
|
-
self.dismissViewControllerAnimated true, completion:nil
|
|
1204
|
-
end
|
|
1013
|
+
# file operations
|
|
1014
|
+
"my.plist".exists? # => NSFileManager.defaultManager.fileExistsAtPath("my.plist")
|
|
1015
|
+
"my.plist".document # => NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true)[0].stringByAppendingPathComponent("my.plist")
|
|
1016
|
+
"my.plist".cache # => NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, true)[0].stringByAppendingPathComponent("my.plist")
|
|
1017
|
+
"my.plist".remove! # => NSFileManager.defaultManager.removeItemAtPath("my.plist".document, error: error) (returns error, if any occurred)
|
|
1205
1018
|
|
|
1206
|
-
# the
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
.
|
|
1211
|
-
.
|
|
1212
|
-
.
|
|
1213
|
-
UIBarButtonItem.pagecurl { ... } => UIBarButtonItem.alloc.initWithBarButtonSystemItem(:pagecurl.uibarbuttonitem, target:self, action:"action:")
|
|
1019
|
+
# get the resource path, useful if you include json files or images you manipulate in the app
|
|
1020
|
+
"my.plist".resource # => NSBundle.mainBundle.resourcePath.stringByAppendingPathComponent("my.plist")
|
|
1021
|
+
# same, but get a URL instead - often used to display a static HTML page that is stored in resources
|
|
1022
|
+
"index.html".resource_url # => NSBundle.mainBundle.URLForResource("index", withExtension:"html")
|
|
1214
1023
|
|
|
1215
|
-
#
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
end
|
|
1219
|
-
# =>
|
|
1220
|
-
UIBarButtonItem.alloc.initWithTitle('Close', style: :bordered.uibarbuttonstyle, target:self, action:"action:")
|
|
1221
|
-
def action(sender)
|
|
1222
|
-
self.dismissViewControllerAnimated(true, completion:nil)
|
|
1223
|
-
end
|
|
1024
|
+
# access data from Info.plist
|
|
1025
|
+
"CFBundleVersion".info_plist # => NSBundle.mainBundle.infoDictionary["CFBundleVersion"]
|
|
1026
|
+
```
|
|
1224
1027
|
|
|
1028
|
+
Localized
|
|
1029
|
+
-----
|
|
1225
1030
|
|
|
1226
|
-
|
|
1227
|
-
UIBarButtonItem.titled('Close', :plain) do # :plain, :bordered, :done
|
|
1228
|
-
# ...
|
|
1229
|
-
end
|
|
1031
|
+
> `require 'sugarcube-localized'`
|
|
1230
1032
|
|
|
1033
|
+
```ruby
|
|
1034
|
+
# NSLocalizedString from string
|
|
1035
|
+
"hello".localized # => NSBundle.mainBundle.localizedStringForKey("hello", value:nil, table:nil)
|
|
1036
|
+
"hello"._ # == "hello".localized
|
|
1037
|
+
"hello".localized('Hello!', 'hello_table') # => ...("hello", value:'Hello!', table:'hello_table')
|
|
1231
1038
|
|
|
1232
|
-
#
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
# =>
|
|
1237
|
-
UIBarButtonItem.alloc.initWithImage('Close'.uiimage, style: :bordered.uibarbuttonstyle, ...)
|
|
1039
|
+
# If you have an NSError object, you can retrieve the localizedDescription the same way:
|
|
1040
|
+
error.localized
|
|
1041
|
+
error._
|
|
1042
|
+
```
|
|
1238
1043
|
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
# ...
|
|
1242
|
-
end
|
|
1044
|
+
NSCoder
|
|
1045
|
+
-----
|
|
1243
1046
|
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1047
|
+
Shorthands and hash-like access to the coder/decoder objects.
|
|
1048
|
+
|
|
1049
|
+
> `require 'sugarcube-nscoder'`
|
|
1050
|
+
|
|
1051
|
+
```ruby
|
|
1052
|
+
# hash access is the handiest
|
|
1053
|
+
coder['key'] = self.value
|
|
1054
|
+
self.value = decoder['key']
|
|
1055
|
+
|
|
1056
|
+
# but if you want to store booleans and such (in their C form,
|
|
1057
|
+
# which will take up less space):
|
|
1058
|
+
coder.set('sugarcube_is_neat', toBool: self.sugarcube_is_neat?)
|
|
1059
|
+
self.sugarcube_is_neat = decoder.bool('sugarcube_is_neat')
|
|
1060
|
+
|
|
1061
|
+
coder.set('number_of_things', toInt:self.number_of_things)
|
|
1062
|
+
self.number_of_things = decoder.int('number_of_things')
|
|
1063
|
+
|
|
1064
|
+
# the entire list:
|
|
1065
|
+
coder.set(key, toBool:value)
|
|
1066
|
+
coder.set(key, toDouble:value)
|
|
1067
|
+
coder.set(key, toFloat:value)
|
|
1068
|
+
coder.set(key, toInt:value)
|
|
1069
|
+
coder.set(key, toPoint:value)
|
|
1070
|
+
coder.set(key, toRect:value)
|
|
1071
|
+
coder.set(key, toSize:value)
|
|
1072
|
+
|
|
1073
|
+
decoder.bool(key)
|
|
1074
|
+
decoder.double(key)
|
|
1075
|
+
decoder.float(key)
|
|
1076
|
+
decoder.int(key)
|
|
1077
|
+
decoder.point(key)
|
|
1078
|
+
decoder.rect(key)
|
|
1079
|
+
decoder.size(key)
|
|
1250
1080
|
```
|
|
1251
1081
|
|
|
1252
|
-
|
|
1082
|
+
NSData
|
|
1083
|
+
-----
|
|
1084
|
+
|
|
1085
|
+
> `require 'sugarcube-nsdata'`
|
|
1086
|
+
|
|
1087
|
+
Going to and from `NSData` is really useful when doing HTTP posts.
|
|
1088
|
+
|
|
1253
1089
|
```ruby
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1090
|
+
# default string encoding is UTF8, you can pass other encodings to this method
|
|
1091
|
+
string_data = 'String'.nsdata
|
|
1092
|
+
|
|
1093
|
+
# PNG data representation
|
|
1094
|
+
image = 'an image'.uiimage
|
|
1095
|
+
image_data = image.nsdata
|
|
1096
|
+
|
|
1097
|
+
# this will download the URL contents
|
|
1098
|
+
url = 'http://localhost'.nsurl
|
|
1099
|
+
url.nsdata # => NSData.dataWithContentsOfURL(self)
|
|
1100
|
+
|
|
1101
|
+
string_data.nsstring # => 'String'
|
|
1102
|
+
image_data.nsimage # => whatever 'an image' was
|
|
1260
1103
|
```
|
|
1261
1104
|
|
|
1262
|
-
|
|
1263
|
-
|
|
1105
|
+
NSDate ([wiki][NSDate Wiki])
|
|
1106
|
+
-----
|
|
1264
1107
|
|
|
1265
|
-
|
|
1108
|
+
> `require 'sugarcube-nsdate'`
|
|
1266
1109
|
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
MyNotification.post_notification # => NSNotificationCenter.defaultCenter.postNotificationName(MyNotification, object:nil)
|
|
1271
|
-
MyNotification.post_notification(obj) # => NSNotificationCenter.defaultCenter.postNotificationName(MyNotification, object:obj)
|
|
1272
|
-
MyNotification.post_notification(obj, user: 'dict') # => NSNotificationCenter.defaultCenter.postNotificationName(MyNotification, object:obj, userInfo:{user: 'dict'})
|
|
1110
|
+
This package includes additions to the `NSDate` class, and related additions to
|
|
1111
|
+
`Fixnum` and `NSString`. There's a lot here, so check out the [wiki][NSDate Wiki]
|
|
1112
|
+
for detailed information.
|
|
1273
1113
|
|
|
1274
|
-
|
|
1275
|
-
def notified(notification)
|
|
1276
|
-
notification[:user] # => 'dict'
|
|
1277
|
-
end
|
|
1114
|
+
[NSDate Wiki]: https://github.com/rubymotion/sugarcube/wiki/NSDate
|
|
1278
1115
|
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
MyNotification.add_observer(observer, :method_name, object)
|
|
1116
|
+
Foundation
|
|
1117
|
+
-----
|
|
1282
1118
|
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1119
|
+
Smaller additions to the CoreFoundation classes. Some extensions, like
|
|
1120
|
+
`NSDate`, are large enough that they get broken out into their own packages.
|
|
1121
|
+
|
|
1122
|
+
> `require 'sugarcube-foundation'`
|
|
1123
|
+
|
|
1124
|
+
###### NSArray
|
|
1125
|
+
```ruby
|
|
1126
|
+
[1, 3].nsindexpath # NSIndexPath.indexPathWithIndex(1).indexPathByAddingIndex(3)
|
|
1127
|
+
[1, 3].nsindexset
|
|
1128
|
+
[1, 3].nsset
|
|
1286
1129
|
```
|
|
1287
1130
|
|
|
1288
|
-
|
|
1289
|
-
|
|
1131
|
+
###### NSIndexSet
|
|
1132
|
+
```ruby
|
|
1133
|
+
index_set.to_a # => [1, 2, ...]
|
|
1134
|
+
```
|
|
1290
1135
|
|
|
1136
|
+
###### NSIndexPath
|
|
1291
1137
|
```ruby
|
|
1292
|
-
#
|
|
1293
|
-
|
|
1294
|
-
@view.shake
|
|
1295
|
-
end
|
|
1296
|
-
# repeating
|
|
1297
|
-
1.second.every do
|
|
1298
|
-
@view.shake
|
|
1299
|
-
end
|
|
1138
|
+
index_path.to_a # => [1, 2, ...]
|
|
1139
|
+
```
|
|
1300
1140
|
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1141
|
+
###### NSString
|
|
1142
|
+
```ruby
|
|
1143
|
+
'https://github.com'.nsurl
|
|
1144
|
+
'/path/to/file'.fileurl
|
|
1145
|
+
'https://google.com/search?q=' + 'search terms'.escape_url
|
|
1146
|
+
'%20'.unescape_url
|
|
1147
|
+
```
|
|
1307
1148
|
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1149
|
+
###### NSURL
|
|
1150
|
+
```ruby
|
|
1151
|
+
url = 'https://github.com'.nsurl
|
|
1152
|
+
url.can_open? # => true, it will open in safari
|
|
1153
|
+
url.open # opens in safari
|
|
1154
|
+
url.nsurlrequest # convert to NSURLRequest object
|
|
1155
|
+
```
|
|
1314
1156
|
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
puts "ding!"
|
|
1318
|
-
end
|
|
1157
|
+
IndexPath
|
|
1158
|
+
-----
|
|
1319
1159
|
|
|
1320
|
-
|
|
1321
|
-
# for compatibility with Time methods, the mins/secs (and min/sec) aliases are provided. Personally,
|
|
1322
|
-
# I like the more verbose minutes/seconds.
|
|
1323
|
-
1.millisecond || 2.milliseconds
|
|
1324
|
-
1.millisec || 2.millisecs
|
|
1325
|
-
1.second || 2.seconds
|
|
1326
|
-
1.sec || 2.secs # aliases
|
|
1327
|
-
1.minute || 2.minutes # 1.minute = 60 seconds
|
|
1328
|
-
1.min || 2.mins # aliases
|
|
1329
|
-
1.hour || 2.hours # 1.hour = 60 minutes
|
|
1330
|
-
1.day || 2.days # 1.day = 24 hours
|
|
1331
|
-
1.week || 2.weeks # 1.week = 7 days
|
|
1332
|
-
# sensible values for 'month' and 'year', even though we all know you can't
|
|
1333
|
-
# **really** define them this way (go back to python if you find your brain
|
|
1334
|
-
# hemorrhaging):
|
|
1335
|
-
1.month || 2.months # 1.month = 30 days
|
|
1336
|
-
1.year || 2.years # 1.year = 365 days
|
|
1160
|
+
> `require 'sugarcube-indexpath`
|
|
1337
1161
|
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1162
|
+
Use the `IndexPath` class to match `NSIndexPath` objects, for instance in a
|
|
1163
|
+
`UITableViewDelegate`.
|
|
1164
|
+
|
|
1165
|
+
```ruby
|
|
1166
|
+
index_path = [0, 2].nsindexpath
|
|
1167
|
+
case index_path
|
|
1168
|
+
when IndexPath[0]
|
|
1169
|
+
when IndexPath[1, 0..5]
|
|
1170
|
+
when IndexPath[1, 5..objects.length]
|
|
1171
|
+
end
|
|
1172
|
+
[0, 2].nsindexpath.to_a == [0, 2] # => true
|
|
1341
1173
|
```
|
|
1342
1174
|
|
|
1343
1175
|
NSUserDefaults
|
|
1344
|
-
|
|
1176
|
+
-----
|
|
1177
|
+
|
|
1178
|
+
> `require 'sugarcube-nsuserdefaults'`
|
|
1345
1179
|
|
|
1346
1180
|
This file does *one* thing very **DANGEROUS**... to "help" with defaults.
|
|
1347
1181
|
|
|
@@ -1386,6 +1220,9 @@ NSUserDefaults['test'] = test # saved
|
|
|
1386
1220
|
CoreGraphics
|
|
1387
1221
|
--------------
|
|
1388
1222
|
|
|
1223
|
+
*This package is installed automatically, because so many other packages depend
|
|
1224
|
+
on it. It does not add any methods to built-in classes.*
|
|
1225
|
+
|
|
1389
1226
|
###### Is it `CGMakeRect` or `CGRectMake`? What arguments does `CGRect.new` take?
|
|
1390
1227
|
|
|
1391
1228
|
Instead, just use the coercion methods `Rect()`, `Size()` and `Point()`. They
|
|
@@ -1423,8 +1260,51 @@ f = Rect(p, [w, h])
|
|
|
1423
1260
|
f = Rect([x, y], s)
|
|
1424
1261
|
```
|
|
1425
1262
|
|
|
1263
|
+
Pointer
|
|
1264
|
+
-----
|
|
1265
|
+
|
|
1266
|
+
> `require 'sugarcube-pointer'`
|
|
1267
|
+
|
|
1268
|
+
These are not UIKit-related, so I reverted to Ruby's preferred `to_foo`
|
|
1269
|
+
convention.
|
|
1270
|
+
|
|
1271
|
+
```ruby
|
|
1272
|
+
[0.0, 1.1, 2.2].to_pointer(:float)
|
|
1273
|
+
|
|
1274
|
+
# is equivalent to
|
|
1275
|
+
floats = Pointer.new(:float, 3)
|
|
1276
|
+
floats[0] = 0.0
|
|
1277
|
+
floats[1] = 1.1
|
|
1278
|
+
floats[2] = 2.2
|
|
1279
|
+
```
|
|
1280
|
+
|
|
1281
|
+
To_s
|
|
1282
|
+
-----
|
|
1283
|
+
|
|
1284
|
+
> `require 'sugarcube-to_s'`
|
|
1285
|
+
|
|
1286
|
+
`to_s` methods are defined on the following classes:
|
|
1287
|
+
|
|
1288
|
+
* NSError
|
|
1289
|
+
* NSIndexPath
|
|
1290
|
+
* NSLayoutConstraint
|
|
1291
|
+
* NSNotification
|
|
1292
|
+
* NSSet
|
|
1293
|
+
* NSURL
|
|
1294
|
+
* UIColor
|
|
1295
|
+
* UIEvent
|
|
1296
|
+
* UIView
|
|
1297
|
+
* UILabel
|
|
1298
|
+
* UITextField
|
|
1299
|
+
* UITouch
|
|
1300
|
+
* UIViewController
|
|
1301
|
+
|
|
1302
|
+
The output of these is (much?) more useful than the default.
|
|
1303
|
+
|
|
1426
1304
|
CoreLocation
|
|
1427
|
-
|
|
1305
|
+
-----
|
|
1306
|
+
|
|
1307
|
+
> `require 'sugarcube-corelocation'`
|
|
1428
1308
|
|
|
1429
1309
|
Open up `CLLocationCoordinate2D` to provide handy-dandies
|
|
1430
1310
|
|
|
@@ -1435,7 +1315,7 @@ Open up `CLLocationCoordinate2D` to provide handy-dandies
|
|
|
1435
1315
|
=> #<CLLocationCoordinate2D latitude=39.2681274414062 longitude=-84.2576293945312>
|
|
1436
1316
|
> denver_co.distance_to(loveland_oh)
|
|
1437
1317
|
=> 1773425.5 # in meters
|
|
1438
|
-
> denver_co.distance_to(loveland_oh).
|
|
1318
|
+
> denver_co.distance_to(loveland_oh).in_miles
|
|
1439
1319
|
=> 1101.955078125
|
|
1440
1320
|
> denver_co.delta_miles(1101.6, -32.556)
|
|
1441
1321
|
=> #<CLLocationCoordinate2D latitude=39.2681427001953 longitude=-84.2577209472656>
|
|
@@ -1445,399 +1325,95 @@ Open up `CLLocationCoordinate2D` to provide handy-dandies
|
|
|
1445
1325
|
=> 0.00502094626426697
|
|
1446
1326
|
```
|
|
1447
1327
|
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
Pixel pushing is an unfortunate but necessary evil. Well, at least we can make
|
|
1452
|
-
it a little less painful. SugarCube provides a library that adds some methods
|
|
1453
|
-
that are meant to be used in the REPL.
|
|
1454
|
-
|
|
1455
|
-
`require "sugarcube-repl"`
|
|
1456
|
-
|
|
1457
|
-
The actual code is, for historical reasons, in the `SugarCube::Adjust` module,
|
|
1458
|
-
which is included by default. But to really be handy you'll want to require the
|
|
1459
|
-
`sugarcube-repl` package.
|
|
1460
|
-
|
|
1461
|
-
#### Finding the view you want.
|
|
1462
|
-
|
|
1463
|
-
This is often touted as the *most useful feature* of SugarCube!
|
|
1464
|
-
|
|
1465
|
-
```
|
|
1466
|
-
(main)> tree
|
|
1467
|
-
0: . UIWindow(#6e1f950: [[0.0, 0.0], [320.0, 480.0]])
|
|
1468
|
-
1: `-- UIView(#8b203b0: [[0.0, 20.0], [320.0, 460.0]])
|
|
1469
|
-
2: +-- UIButton(#d028de0: [[10.0, 10.0], [320.0, 463.400512695312]])
|
|
1470
|
-
3: | `-- UIImageView(#d02aaa0: [[0.0, 0.0], [320.0, 463.400512695312]])
|
|
1471
|
-
4: +-- UIRoundedRectButton(#d02adb0: [[55.0, 110.0], [210.0, 20.0]])
|
|
1472
|
-
5: | `-- UIButtonLabel(#d02af00: [[73.0, 0.0], [63.0, 19.0]], text: "Button 1")
|
|
1473
|
-
6: +-- UIRoundedRectButton(#d028550: [[60.0, 30.0], [200.0, 20.0]])
|
|
1474
|
-
7: | `-- UIButtonLabel(#d02afb0: [[68.0, 0.0], [63.0, 19.0]], text: "Button 2")
|
|
1475
|
-
8: `-- UIRoundedRectButton(#d02b220: [[70.0, 30.0], [300.0, 20.0]])
|
|
1476
|
-
9: `-- UIButtonLabel(#d02b300: [[118.0, 0.0], [63.0, 19.0]], text: "Button 3")
|
|
1477
|
-
```
|
|
1478
|
-
|
|
1479
|
-
SugarCube provides lot of `to_s` methods on UIKit objects - that is so that this
|
|
1480
|
-
tree view is really easy to find the view you want. Once you do find the one
|
|
1481
|
-
you want, you can fetch it out of that list using the `adjust` method, which is
|
|
1482
|
-
aliased to `a` to make it easy on the fingers.
|
|
1483
|
-
|
|
1484
|
-
```
|
|
1485
|
-
(main)> a 6
|
|
1486
|
-
=> UIRoundedRectButton(#d028550: [[60.0, 30.0], [200.0, 20.0]]), child of UIView(#8b203b0)
|
|
1487
|
-
```
|
|
1488
|
-
|
|
1489
|
-
Now that we've chose the button, it is available in the `a` method, *and* there
|
|
1490
|
-
are a bunch of methods in the SugarCube::Adjust module that act on that object.
|
|
1491
|
-
Most of these methods help you adjust the frame of a view.
|
|
1492
|
-
|
|
1493
|
-
```ruby
|
|
1494
|
-
> up 1
|
|
1495
|
-
> down 1 # same as `up -1`
|
|
1496
|
-
> down # defaults to 1 anyway
|
|
1497
|
-
> left 10
|
|
1498
|
-
> right 10
|
|
1499
|
-
> left # => left 1
|
|
1500
|
-
> origin 10, 12 # move to x:10, y:12
|
|
1501
|
-
> wider 15
|
|
1502
|
-
> thinner 10
|
|
1503
|
-
> taller # => taller 1
|
|
1504
|
-
> shorter # => shorter 1
|
|
1505
|
-
> size 100, 10 # set size to width:100, height: 10
|
|
1506
|
-
> shadow(opacity: 0.5, offset: [0, 0], color: :black, radius: 1) # and path, which is a CGPath object.
|
|
1507
|
-
> center # See `Centering` section below
|
|
1508
|
-
> restore # original frame and shadow is saved when you first call `adjust`
|
|
1509
|
-
```
|
|
1510
|
-
|
|
1511
|
-
Here are the short versions of those methods.
|
|
1512
|
-
|
|
1513
|
-
```ruby
|
|
1514
|
-
> u # up, default value=1
|
|
1515
|
-
> d # down
|
|
1516
|
-
> l # left
|
|
1517
|
-
> r # right
|
|
1518
|
-
> w # wider
|
|
1519
|
-
> n # thiNNer
|
|
1520
|
-
> t # taller
|
|
1521
|
-
> s # shorter
|
|
1522
|
-
> o 10, 12 # origin
|
|
1523
|
-
> o [10, 12]
|
|
1524
|
-
> o CGPoint.new(10, 12)
|
|
1525
|
-
> o Point(10, 12)
|
|
1526
|
-
> z 100, 10 # siZe, also accepts an array, CGSize, or Size()
|
|
1527
|
-
# and frame
|
|
1528
|
-
> f [[0,0], [0,0]]
|
|
1529
|
-
# sHadow
|
|
1530
|
-
> h opacity: 0.5, offset: [0, 0], color: :black, radius: 1
|
|
1531
|
-
|
|
1532
|
-
# frame, size, origin, and shadow can also be used as getters
|
|
1533
|
-
> f
|
|
1534
|
-
[[0, 0], [320, 568]]
|
|
1535
|
-
> o # origin
|
|
1536
|
-
[0, 0]
|
|
1537
|
-
> z # size
|
|
1538
|
-
[320, 568]
|
|
1539
|
-
> h # this returns an object identical to what you can pass to `shadow`
|
|
1540
|
-
{opacity: 0.5, offset: [0, 0], color: :black, radius: 1}
|
|
1541
|
-
|
|
1542
|
-
# and of course the `a` method returns the current object
|
|
1543
|
-
> a
|
|
1544
|
-
=> UITextField(#9ce6470, [[46, 214], [280, 33]], text: "hi!"), child of UIView(#10a6da20)
|
|
1545
|
-
```
|
|
1546
|
-
|
|
1547
|
-
The most useful feature of the REPL adjustment is the ability to quickly
|
|
1548
|
-
position and size your UI elements __visually__ and then paste the final values
|
|
1549
|
-
into your code. In order to better accomodate that, `adjust` has an option to
|
|
1550
|
-
modify the output format. Many thanks to [Thom Parkin][] for developing these
|
|
1551
|
-
output formatters.
|
|
1552
|
-
|
|
1553
|
-
```
|
|
1554
|
-
(main)> repl_format :ruby
|
|
1555
|
-
```
|
|
1556
|
-
|
|
1557
|
-
Currently supported is:
|
|
1558
|
-
|
|
1559
|
-
* RubyMotion (Default) (`:ruby`)
|
|
1560
|
-
* Objective-C (`:objc`)
|
|
1561
|
-
* JSON (`:json`)
|
|
1562
|
-
|
|
1563
|
-
#### Objective-C style
|
|
1564
|
-
|
|
1565
|
-
```
|
|
1566
|
-
(main)> repl_format :objc
|
|
1567
|
-
(main)> tree
|
|
1568
|
-
0: . UIWindow(#6e27180: {{0, 0}, {320, 480}})
|
|
1569
|
-
1: `-- UIView(#8d631b0: {{0, 20}, {320, 460}})
|
|
1570
|
-
2: +-- UIButton(#6d6c090: {{10, 10}, {320, 463.401}})
|
|
1571
|
-
3: | `-- UIImageView(#8d67e00: {{0, 0}, {320, 463.401}})
|
|
1572
|
-
4: `-- UIRoundedRectButton(#8d68170: {{10, 30}, {30, 200}})
|
|
1573
|
-
5: `-- UIButtonLabel(#8d69c30: {{2, 90}, {26, 19}})
|
|
1574
|
-
=> UIWindow(#6e27180, {{0, 0}, {320, 480}},
|
|
1575
|
-
|
|
1576
|
-
# you can pass the format into the adjust method:
|
|
1577
|
-
(main)> a 4, :objc
|
|
1578
|
-
=> "UIRoundedRectButton(#8d68170: {{10.0, 30.0}, {200.0, 30.0}})"
|
|
1579
|
-
|
|
1580
|
-
# it will continue to be used in subsequent calls
|
|
1581
|
-
(main)> wider 15
|
|
1582
|
-
{{10.0, 30.0}, {200.0, 45.0}}
|
|
1583
|
-
=> "UIRoundedRectButton(#8d68170: {{10.0, 30.0}, {200.0, 45.0}}) child of UIView(#8d631b0)"
|
|
1584
|
-
```
|
|
1585
|
-
|
|
1586
|
-
#### JSON (or GeoMotion)
|
|
1587
|
-
|
|
1588
|
-
```
|
|
1589
|
-
(main)> a 1, :json
|
|
1590
|
-
=> "UIView(#8d631b0: {x: 0.0, y: 20.0, height: 460.0, width: 320.0})"
|
|
1591
|
-
(main)> wider 30
|
|
1592
|
-
=> "CGRect(#6e9c9f0: {x: 0.0, y: 20.0, height: 460.0, width: 350.0})"
|
|
1593
|
-
(main)> right 130
|
|
1594
|
-
=> "CGRect(#8dc6a40: {x: 130.0, y: 20.0, height: 460.0, width: 350.0})"
|
|
1595
|
-
(main)> tree
|
|
1596
|
-
0: . UIWindow(#6e27180: {x: 0.0, y: 0.0, height: 480.0, width: 320.0})
|
|
1597
|
-
1: `-- UIView(#8d631b0: {x: 130.0, y: 20.0, height: 460.0, width: 350.0})
|
|
1598
|
-
2: +-- UIButton(#6d6c090: {x: 10.0, y: 10.0, height: 463.400512695312, width: 320.0})
|
|
1599
|
-
3: | `-- UIImageView(#8d67e00: {x: 0.0, y: 0.0, height: 463.400512695312, width: 320.0})
|
|
1600
|
-
4: `-- UIRoundedRectButton(#8d68170: {x: 10.0, y: 30.0, height: 200.0, width: 45.0})
|
|
1601
|
-
5: `-- UIButtonLabel(#8d69c30: {x: 4.0, y: 90.0, height: 19.0, width: 37.0})
|
|
1602
|
-
=> UIWindow(#6e27180: {x: 0.0, y: 0.0, height: 480.0, width: 320.0})
|
|
1603
|
-
```
|
|
1604
|
-
|
|
1605
|
-
### CENTER (in parent frame)
|
|
1606
|
-
|
|
1607
|
-
It is called as `center(which_index, of_total_number, direction)`. The order can
|
|
1608
|
-
be changed, and all the arguments are optional. Default values are
|
|
1609
|
-
`center(1, 1, 'h')` (center the item horizontally).
|
|
1610
|
-
|
|
1611
|
-
You can set 'direction' using a string or symbol: 'horiz', 'vert', 'x', even 'x
|
|
1612
|
-
and y'. The method searches for the letters `[xyhv]`.
|
|
1613
|
-
|
|
1614
|
-
Here are a few examples:
|
|
1615
|
-
|
|
1616
|
-
```
|
|
1617
|
-
(main)> center
|
|
1618
|
-
[[145.0, 30.0], [30.0, 200.0]]
|
|
1619
|
-
UIRoundedRectButton.origin = [145.0, 30.0]
|
|
1620
|
-
=> "[[145.0, 30.0], [30.0, 200.0]]"
|
|
1621
|
-
```
|
|
1622
|
-
|
|
1623
|
-
In order to place that same button in the center of the screen - horizontally
|
|
1624
|
-
and vertically - you can use this shorthand syntax:
|
|
1625
|
-
|
|
1626
|
-
`center :xy`
|
|
1627
|
-
|
|
1628
|
-
If you have three buttons and want them spaced evenly (vertically) across their
|
|
1629
|
-
parent frame, you can accomplish that this way:
|
|
1630
|
-
|
|
1631
|
-
```
|
|
1632
|
-
(main)> tree
|
|
1633
|
-
0: . UIWindow(#6e1f950: [[0.0, 0.0], [320.0, 480.0]])
|
|
1634
|
-
1: `-- UIView(#8b203b0: [[0.0, 20.0], [320.0, 460.0]])
|
|
1635
|
-
2: +-- UIButton(#d028de0: [[10.0, 10.0], [320.0, 464]])
|
|
1636
|
-
3: | `-- UIImageView(#d02aaa0: [[0.0, 0.0], [320.0, 464]])
|
|
1637
|
-
4: +-- UIRoundedRectButton(#d02adb0: [[55.0, 110.0], [210.0, 20.0]], text: "Button 1")
|
|
1638
|
-
5: | `-- UIButtonLabel(#d02af00: [[73.0, 0.0], [63.0, 19.0]])
|
|
1639
|
-
6: +-- UIRoundedRectButton(#d028550: [[60.0, 30.0], [200.0, 20.0]], text: "Button 2")
|
|
1640
|
-
7: | `-- UIButtonLabel(#d02afb0: [[68.0, 0.0], [63.0, 19.0]])
|
|
1641
|
-
8: `-- UIRoundedRectButton(#d02b220: [[70.0, 30.0], [300.0, 20.0]], text: "Button 3")
|
|
1642
|
-
9: `-- UIButtonLabel(#d02b300: [[118.0, 0.0], [63.0, 19.0]])
|
|
1643
|
-
=> UIWindow(#6e1f950, [[0.0, 0.0], [320.0, 480.0]])
|
|
1644
|
-
# grab the first button, and center it vertically. It is the first of three buttons
|
|
1645
|
-
(main)> a 4; center 1, 3, :vert; center
|
|
1646
|
-
[[55.0, 110.0], [210.0, 20.0]]
|
|
1647
|
-
UIRoundedRectButton.origin = [55.0, 110.0]
|
|
1648
|
-
=> "[[55.0, 110.0], [210.0, 20.0]]"
|
|
1649
|
-
# grab the second button. The first parameter changes to `2`, because this
|
|
1650
|
-
# button is in the second position.
|
|
1651
|
-
(main)> a 6; center 2, 3, :vert; center
|
|
1652
|
-
[[60.0, 220.0], [200.0, 20.0]]
|
|
1653
|
-
UIRoundedRectButton.origin = [60.0, 220.0]
|
|
1654
|
-
=> "[[60.0, 220.0], [200.0, 20.0]]"
|
|
1655
|
-
# grab the third button and place it in the third position
|
|
1656
|
-
(main)> a 8; center 3, 3, :vert; center
|
|
1657
|
-
[[10.0, 330.0], [300.0, 20.0]]
|
|
1658
|
-
UIRoundedRectButton.origin = [10.0, 330.0]
|
|
1659
|
-
=> "[[10.0, 330.0], [300.0, 20.0]]"
|
|
1660
|
-
```
|
|
1661
|
-
|
|
1662
|
-
The calculated positions (x,y) are in the REPL output
|
|
1663
|
-
|
|
1664
|
-
#### Finding the *[controller,layer,...]* you want.
|
|
1665
|
-
|
|
1666
|
-
**Don't stop there!**
|
|
1328
|
+
Pipes
|
|
1329
|
+
-----
|
|
1667
1330
|
|
|
1668
|
-
|
|
1669
|
-
|
|
1331
|
+
This package short-circuits the `|` operator to perform coercion and filtering
|
|
1332
|
+
between all sorts of objects.
|
|
1670
1333
|
|
|
1671
|
-
|
|
1672
|
-
(main)> tree root
|
|
1673
|
-
0: . #<MainScreenController:0xac23b80>
|
|
1674
|
-
1: +-- #<ScheduleViewController:0x13185d00>
|
|
1675
|
-
2: | +-- #<ScheduleTableController:0x131862f0>
|
|
1676
|
-
3: | `-- #<ScheduleCalendarController:0x131bba90>
|
|
1677
|
-
4: +-- #<CameraViewController:0x13191380>
|
|
1678
|
-
5: +-- #<UINavigationController:0xac01ea0>
|
|
1679
|
-
6: | `-- #<UITableViewController:0xac04e30>
|
|
1680
|
-
7: +-- #<PicturesViewController:0x1403ede0>
|
|
1681
|
-
8: `-- #<MessagesViewController:0x131a1bc0>
|
|
1682
|
-
=> #<MainScreenController:0xac23b80>
|
|
1683
|
-
```
|
|
1334
|
+
### Coercion
|
|
1684
1335
|
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
block will be passed your object, and should return the children.
|
|
1336
|
+
Any object that defines a coercion method (image.uicolor, string.uiimage,
|
|
1337
|
+
:symbol.uifont) can use the `|` and the class name to perform the same method.
|
|
1688
1338
|
|
|
1689
1339
|
```ruby
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
```
|
|
1694
|
-
```
|
|
1695
|
-
(main)> foo = Foo.new
|
|
1696
|
-
(main)> foo.children = [Foo.new,Foo.new,Foo.new]
|
|
1697
|
-
(main)> tree foo, :children
|
|
1698
|
-
(main)> tree foo, :children
|
|
1699
|
-
0: . #<Foo:0x12d6e0d0>
|
|
1700
|
-
1: +-- #<Foo:0x114146c0>
|
|
1701
|
-
2: +-- #<Foo:0x114149d0>
|
|
1702
|
-
3: `-- #<Foo:0x114149e0>
|
|
1703
|
-
|
|
1704
|
-
=> #<Foo:0x12d6e0d0 @children=[#<Foo:0x114146c0>, #<Foo:0x114149d0>, #<Foo:0x114149e0>]>
|
|
1705
|
-
(main)> tree(foo) { |f| f.children }
|
|
1706
|
-
0: . #<Foo:0x12d6e0d0>
|
|
1707
|
-
1: +-- #<Foo:0x114146c0>
|
|
1708
|
-
2: +-- #<Foo:0x114149d0>
|
|
1709
|
-
3: `-- #<Foo:0x114149e0>
|
|
1710
|
-
|
|
1711
|
-
=> #<Foo:0x12d6e0d0 @children=[#<Foo:0x114146c0>, #<Foo:0x114149d0>, #<Foo:0x114149e0>]>
|
|
1340
|
+
:label | UIFont # => # :label.uifont
|
|
1341
|
+
"image_name" | UIImage # => "image_name".uiimage
|
|
1342
|
+
view | UIImage | UIColor # => view.uiimage.uicolor
|
|
1712
1343
|
```
|
|
1713
1344
|
|
|
1714
|
-
|
|
1345
|
+
### Filters
|
|
1715
1346
|
|
|
1716
|
-
|
|
1717
|
-
|
|
1347
|
+
You can pipe objects that have some idea of "filter", like using an image mask
|
|
1348
|
+
or image filter.
|
|
1718
1349
|
|
|
1719
1350
|
```ruby
|
|
1720
|
-
|
|
1721
|
-
|
|
1351
|
+
image | mask # => image.masked(mask)
|
|
1352
|
+
image | darken_cifilter # => image.apply_filter(darken_cifilter)
|
|
1353
|
+
# this one is... interesting!
|
|
1354
|
+
"My name is Mud" | /\w+$/ # => "Mud"
|
|
1355
|
+
"My name is Mud" | /\d+$/ # => nil
|
|
1356
|
+
"My name is Mud" | "Mud" # => "Mud"
|
|
1357
|
+
"My name is Mud" | "Bob" # => nil
|
|
1722
1358
|
```
|
|
1723
1359
|
|
|
1360
|
+
Awesome
|
|
1361
|
+
-----
|
|
1724
1362
|
|
|
1725
|
-
|
|
1726
|
-
----------
|
|
1727
|
-
|
|
1728
|
-
These are not UIKit-related, so I reverted to Ruby's preferred `to_foo`
|
|
1729
|
-
convention.
|
|
1730
|
-
|
|
1731
|
-
```ruby
|
|
1732
|
-
[0.0, 1.1, 2.2].to_pointer(:float)
|
|
1733
|
-
|
|
1734
|
-
# is equivalent to
|
|
1735
|
-
floats = Pointer.new(:float, 3)
|
|
1736
|
-
floats[0] = 0.0
|
|
1737
|
-
floats[1] = 1.1
|
|
1738
|
-
floats[2] = 2.2
|
|
1739
|
-
```
|
|
1363
|
+
> `require 'sugarcube-awesome'`
|
|
1740
1364
|
|
|
1741
|
-
|
|
1742
|
-
|
|
1365
|
+
SugarCube adds support for [Motion-Awesome][motion-awesome]! The `awesome_icon`
|
|
1366
|
+
method is added to `Symbol`, which returns an NSAttributedString that uses the
|
|
1367
|
+
MotionAwesome font. You can pass in `:size` and `:color` options.
|
|
1743
1368
|
|
|
1744
|
-
|
|
1745
|
-
`
|
|
1369
|
+
`sugarcube-attributedstring` is not required for this extension to function, but
|
|
1370
|
+
it adds `NSAttributedString` methods that really help. Below I'm usind `#+` and
|
|
1371
|
+
`#bold` and `#color` to construct an `NSAttributedString`.
|
|
1746
1372
|
|
|
1747
1373
|
```ruby
|
|
1748
|
-
|
|
1749
|
-
|
|
1374
|
+
# in Rakefile
|
|
1375
|
+
require 'sugarcube-awesome'
|
|
1376
|
+
require 'sugarcube-attributedstring'
|
|
1750
1377
|
|
|
1751
|
-
#
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1378
|
+
# in your app
|
|
1379
|
+
label.attributedText = (:down_arrow.awesome_icon + ' Going down?'.bold).color(:white)
|
|
1380
|
+
# OR for buttons
|
|
1381
|
+
button.setAttributedTitle(:twitter.awesome_icon, forState:UIControlStateNormal)
|
|
1755
1382
|
```
|
|
1756
1383
|
|
|
1757
|
-
|
|
1758
|
-
---------------
|
|
1759
|
-
|
|
1760
|
-
aka `ActiveSupport`. Now that Thomas Kadauke has released [motion-support][],
|
|
1761
|
-
consider these extensions deprecated. They will be removed in version 1.0.
|
|
1762
|
-
|
|
1763
|
-
```ruby
|
|
1764
|
-
# truthiness with `blank?`
|
|
1765
|
-
nil.blank? # => true
|
|
1766
|
-
false.blank? # => true
|
|
1767
|
-
''.blank? # => true
|
|
1768
|
-
[].blank? # => true
|
|
1769
|
-
{}.blank? # => true
|
|
1770
|
-
|
|
1771
|
-
0.blank? # => false
|
|
1772
|
-
true.blank? # => false
|
|
1773
|
-
'a'.blank? # => false
|
|
1774
|
-
['a'].blank? # => false
|
|
1775
|
-
{a: 'a'}.blank? # => false
|
|
1776
|
-
|
|
1777
|
-
# and my favorite
|
|
1778
|
-
1.in? [1,2,3] # => true
|
|
1779
|
-
1.in? 4..5 # => false
|
|
1780
|
-
```
|
|
1384
|
+
[motion-awesome]: http://derailed.github.io/motion-awesome/
|
|
1781
1385
|
|
|
1782
|
-
|
|
1783
|
-
|
|
1386
|
+
Anonymous
|
|
1387
|
+
-----
|
|
1784
1388
|
|
|
1785
|
-
|
|
1786
|
-
possible that the two will be merged into one thing. But SugarCube is all about
|
|
1787
|
-
extending base classes, whereas BubbleWrap tends to add *new* classes to do the
|
|
1788
|
-
heavy lifting. Plus the options you pass to SugarCube are very different, and
|
|
1789
|
-
the prefix is "on" instead of "when" (e.g. "on_pan" instead of "when_panned")
|
|
1389
|
+
> `require 'sugarcube-anonymous'`
|
|
1790
1390
|
|
|
1791
|
-
|
|
1792
|
-
`
|
|
1391
|
+
Convert `Hash`es into an "anonymous object". Existing keys will be able to be
|
|
1392
|
+
accessed using method names. Uses the `SugarCube::Anonymous` class to
|
|
1393
|
+
accomplish this, though the usual interface is via `Hash#to_object`.
|
|
1793
1394
|
|
|
1794
1395
|
```ruby
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
view.on_pan { |gesture|
|
|
1798
|
-
location = gesture.view.locationInView(view)
|
|
1799
|
-
}
|
|
1800
|
-
|
|
1801
|
-
# other gesture methods, with common options:
|
|
1802
|
-
view.on_tap # use system defaults
|
|
1803
|
-
view.on_tap(1) # number of taps
|
|
1804
|
-
view.on_tap(taps: 1, fingers: 1) # number of taps and number of fingers
|
|
1805
|
-
|
|
1806
|
-
view.on_pinch # no options
|
|
1807
|
-
view.on_rotate # no options
|
|
1808
|
-
|
|
1809
|
-
view.on_swipe # use system defaults
|
|
1810
|
-
view.on_swipe :left
|
|
1811
|
-
view.on_swipe(direction: :left, fingers: 1)
|
|
1812
|
-
view.on_swipe(direction: UISwipeGestureRecognizerDirectionLeft, fingers: 1)
|
|
1396
|
+
h = { foo: 'FOO', 'bar' => 'BAR' }.to_object
|
|
1813
1397
|
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1398
|
+
# You can use methods instead of keys.
|
|
1399
|
+
h.foo # => h[:foo]
|
|
1400
|
+
h.bar # => h['bar']
|
|
1401
|
+
h.foo = 'Foo' # => h[:foo] = 'Foo'
|
|
1402
|
+
h.bar = 'Bar' # => h['bar'] = 'Bar'
|
|
1818
1403
|
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1404
|
+
# only existing keys are accessed this way
|
|
1405
|
+
h.baz # => NoMethodError
|
|
1406
|
+
h.baz = 'baz' # => NoMethodError
|
|
1822
1407
|
```
|
|
1823
1408
|
|
|
1824
1409
|
Unholy
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
These methods are just about as opinionated as they get - even more than the RoR
|
|
1828
|
-
additions. They are not included by default, so please don't freak out about
|
|
1829
|
-
them. I add them here because I don't think anyone will notice if I do, and I
|
|
1830
|
-
use these everywhere. :poop:
|
|
1831
|
-
|
|
1832
|
-
### `ivar`
|
|
1833
|
-
|
|
1834
|
-
###### Rakefile
|
|
1410
|
+
-----
|
|
1835
1411
|
|
|
1836
|
-
|
|
1837
|
-
require 'sugarcube-unholy'
|
|
1838
|
-
```
|
|
1412
|
+
> `require 'sugarcube-unholy'`
|
|
1839
1413
|
|
|
1840
|
-
|
|
1414
|
+
I added these a long time ago to SugarCube, and so it's possible some people use
|
|
1415
|
+
these extensions. Honestly, I should have put them somewhere else, they are
|
|
1416
|
+
silly and not terribly useful, except maybe to me (I use them a lot!). :poop:
|
|
1841
1417
|
|
|
1842
1418
|
```ruby
|
|
1843
1419
|
class Baz ; end
|
|
@@ -1847,10 +1423,25 @@ foo = Baz.new
|
|
|
1847
1423
|
foo.instance_variable_set(:bar.ivar, value) # => foo.instance_variable_set(:@bar, value)
|
|
1848
1424
|
foo.instance_variable_set(var_name.ivar, value) # => foo.instance_variable_set("@#{var_name}", value)
|
|
1849
1425
|
|
|
1426
|
+
# (:symbol || 'string').setter
|
|
1427
|
+
foo.send(varname.setter, 'value')
|
|
1428
|
+
|
|
1850
1429
|
# (:symbol || 'string').cvar
|
|
1851
1430
|
Baz.class_variable_set(var_name.cvar, value) # => Baz.class_variable_set("@@#{var_name}", value)
|
|
1852
1431
|
```
|
|
1853
1432
|
|
|
1433
|
+
Legacy
|
|
1434
|
+
-----
|
|
1435
|
+
|
|
1436
|
+
> `require 'sugarcube-legacy'`
|
|
1437
|
+
|
|
1438
|
+
This is where deprecated methods go to suffer a long, slow death.
|
|
1439
|
+
|
|
1440
|
+
Contributions
|
|
1441
|
+
=====
|
|
1442
|
+
|
|
1443
|
+
If you want to see new features, please fork, commit, and pull-request! :smiley:
|
|
1444
|
+
|
|
1854
1445
|
[BubbleWrap]: https://github.com/rubymotion/BubbleWrap
|
|
1855
1446
|
[sweettea]: https://github.com/colinta/sweettea
|
|
1856
1447
|
[teacup]: https://github.com/rubymotion/teacup
|