sugarcube 0.20.25 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Build Status](https://travis-ci.org/rubymotion/sugarcube.png)](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
|