sugarcube 1.1.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +1 -1
- data/README.md +73 -10
- data/lib/sugarcube-animations/caanimation.rb +31 -0
- data/lib/sugarcube-animations/calayer.rb +7 -0
- data/lib/sugarcube-animations/uiview.rb +59 -34
- data/lib/sugarcube-attributedstring/nsattributedstring.rb +7 -0
- data/lib/sugarcube-color/nsstring.rb +1 -1
- data/lib/sugarcube-color/symbol.rb +2 -2
- data/lib/sugarcube-color/uicolor.rb +56 -10
- data/lib/sugarcube-corelocation/core_location.rb +12 -3
- data/lib/sugarcube-factories/uiactionsheet.rb +5 -4
- data/lib/sugarcube-factories/uialertview.rb +4 -5
- data/lib/sugarcube-image/ciimage.rb +2 -3
- data/lib/sugarcube-image/uiimage.rb +245 -97
- data/lib/sugarcube-nsdate/date_parser.rb +14 -12
- data/lib/sugarcube-nsdate/nsstring.rb +5 -0
- data/lib/sugarcube-nsdate/{fixnum.rb → numeric.rb} +12 -3
- data/lib/sugarcube-numbers/numeric.rb +7 -0
- data/lib/sugarcube-to_s/uilabel.rb +1 -1
- data/lib/sugarcube-to_s/uiview.rb +1 -2
- data/lib/sugarcube-uikit/uiview.rb +75 -5
- data/lib/sugarcube/version.rb +1 -1
- data/spec/nsattributedstring_spec.rb +4 -0
- data/spec/nsstring_files_spec.rb +18 -15
- data/spec/uiactionsheet_spec.rb +40 -2
- data/spec/uialertview_spec.rb +10 -3
- data/spec/uicolor_spec.rb +39 -0
- data/spec/uiimage_spec.rb +471 -0
- data/spec/uiview_spec.rb +90 -22
- metadata +9 -3
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -171,8 +171,9 @@ A big package chock full of methods to make working in UIKit a joy.
|
|
171
171
|
A few varieties of methods are in this package:
|
172
172
|
|
173
173
|
* Conversions: `'string-to'.uiimage`, `image.uiimageview`
|
174
|
-
* Helpers: shorthands for common operations, like `a_view << a_subview`
|
174
|
+
* Helpers: shorthands for common operations, like `a_view << a_subview`, `a_subview.convert_frame_to(a_view)`
|
175
175
|
* Symbols: `:system.uifont(20)`, `:label.uifontsize`
|
176
|
+
* Frame accessors: `a_view.x`, `a_view.x = 100`
|
176
177
|
|
177
178
|
There are too many methods to define here. Instead: a complete list of methods
|
178
179
|
is available in the [documentation][], and the [wiki page][UIKit Wiki] is a
|
@@ -451,8 +452,22 @@ image.stretchable(insets)
|
|
451
452
|
# will be made transparent, and black opaque.
|
452
453
|
image.masked(mask_image)
|
453
454
|
|
455
|
+
# Apply a color overlay to an image. This is used used on icons (PNG's), on which
|
456
|
+
# you want to change the color.
|
457
|
+
image.overlay(UIColor.redColor)
|
458
|
+
image.overlay(:red)
|
459
|
+
|
454
460
|
# Combine two images
|
455
461
|
image_ab = image_a << image_b
|
462
|
+
|
463
|
+
# Create an image from scratch!
|
464
|
+
UIImage.canvas([100, 100]) do |context| # opaque: false, scale: UIScreen.mainScreen.scale
|
465
|
+
# draw here!
|
466
|
+
end
|
467
|
+
# use an image as a background to draw on
|
468
|
+
image.draw do |context|
|
469
|
+
# draw here!
|
470
|
+
end
|
456
471
|
```
|
457
472
|
|
458
473
|
###### CIFilter additions
|
@@ -546,6 +561,15 @@ These methods are added onto the UIColor class:
|
|
546
561
|
:white.uicolor.mix_with(:black.uicolor, 0.75) # => 0xbfbfbf.uicolor
|
547
562
|
:white.uicolor.mix_with(:black.uicolor, 1) # => :black
|
548
563
|
|
564
|
+
# you can get information about a color:
|
565
|
+
:cyan.uicolor.red # => 0
|
566
|
+
:cyan.uicolor.green # => 1
|
567
|
+
:cyan.uicolor.blue # => 1
|
568
|
+
:cyan.uicolor.hue # => 0.5
|
569
|
+
:cyan.uicolor.saturation # => 1.0
|
570
|
+
:cyan.uicolor.brightness # => 1.0
|
571
|
+
:cyan.uicolor(0.9).alpha # => 0.9
|
572
|
+
|
549
573
|
# convert to CGColor
|
550
574
|
color.cgcolor
|
551
575
|
```
|
@@ -796,8 +820,9 @@ view.tumble # great way to dismiss an alert-like-view
|
|
796
820
|
|
797
821
|
These helpers all delegate to the `UIView.animate` method, which accepts all the
|
798
822
|
options that `UIView.animateWithDuration(delay:options:animations:completion:)`
|
799
|
-
|
800
|
-
|
823
|
+
or `UIView.animateWithDuration(delay:usingSpringWithDamping:initialSpringVelocity:options:animations:completion:)`
|
824
|
+
accept. All options are optional, and they will play nicely inside an animation
|
825
|
+
chain (see below, and the wiki page).
|
801
826
|
|
802
827
|
```ruby
|
803
828
|
UIView.animate do
|
@@ -805,6 +830,23 @@ UIView.animate do
|
|
805
830
|
end
|
806
831
|
```
|
807
832
|
|
833
|
+
The "spring" animations use the method `UIView.animateWithDuration(delay:usingSpringWithDamping:initialSpringVelocity:options:animations:completion:)`,
|
834
|
+
available in iOS 7. In testing, I've found this method to be slightly
|
835
|
+
unreliable, so use with caution. To "enable" it, pass in the `:damping` option.
|
836
|
+
You can also use `:velocity` to set an initial velocity, if there is an
|
837
|
+
animation in progress.
|
838
|
+
|
839
|
+
```ruby
|
840
|
+
new_frame = [[110, 200], [100, 20]]
|
841
|
+
|
842
|
+
UIView.animate(damping: 0.1) do # default velocity is 0
|
843
|
+
view.frame = new_frame
|
844
|
+
end
|
845
|
+
|
846
|
+
# equivalent:
|
847
|
+
view.reframe_to(new_frame, damping: 0.1, velocity: 1)
|
848
|
+
```
|
849
|
+
|
808
850
|
The [wiki] page documents all the different animation methods, and documents
|
809
851
|
animation chaining, which looks like this:
|
810
852
|
|
@@ -819,6 +861,14 @@ end.and_then do
|
|
819
861
|
end.start
|
820
862
|
```
|
821
863
|
|
864
|
+
Core Animation classes get some love, too!
|
865
|
+
|
866
|
+
```ruby
|
867
|
+
view.layer.basic_animation('opacity', from: 0, to: 1, duration: 0.1)
|
868
|
+
```
|
869
|
+
|
870
|
+
Lots more information in the Wiki!
|
871
|
+
|
822
872
|
[Animations Wiki]: https://github.com/rubymotion/sugarcube/wiki/Animations
|
823
873
|
|
824
874
|
Modal
|
@@ -947,6 +997,13 @@ e.g. 1024 bytes in a kilobyte.
|
|
947
997
|
1.megabyte.in_kilobytes # => 1024
|
948
998
|
```
|
949
999
|
|
1000
|
+
### Screen
|
1001
|
+
|
1002
|
+
```ruby
|
1003
|
+
1.pixel # => 1 on non-retina, 0.5 on retina.
|
1004
|
+
# Useful when drawing if you want to specify the number of pixels
|
1005
|
+
```
|
1006
|
+
|
950
1007
|
AttributedString
|
951
1008
|
-----
|
952
1009
|
|
@@ -1113,8 +1170,8 @@ NSDate ([wiki][NSDate Wiki])
|
|
1113
1170
|
> `require 'sugarcube-nsdate'`
|
1114
1171
|
|
1115
1172
|
This package includes additions to the `NSDate` class, and related additions to
|
1116
|
-
`
|
1117
|
-
for detailed information.
|
1173
|
+
`Numeric` and `NSString`. There's a lot here, so check out the [wiki][NSDate
|
1174
|
+
Wiki] for detailed information.
|
1118
1175
|
|
1119
1176
|
[NSDate Wiki]: https://github.com/rubymotion/sugarcube/wiki/NSDate
|
1120
1177
|
|
@@ -1314,20 +1371,26 @@ CoreLocation
|
|
1314
1371
|
Open up `CLLocationCoordinate2D` to provide handy-dandies
|
1315
1372
|
|
1316
1373
|
```ruby
|
1374
|
+
# distances
|
1375
|
+
|
1317
1376
|
> denver_co = CLLocationCoordinate2D.new(39.739188,-104.985223)
|
1318
1377
|
=> #<CLLocationCoordinate2D latitude=39.7391815185547 longitude=-104.985198974609>
|
1319
1378
|
> loveland_oh = CLLocationCoordinate2D.new(39.268128,-84.257648)
|
1320
1379
|
=> #<CLLocationCoordinate2D latitude=39.2681274414062 longitude=-84.2576293945312>
|
1321
1380
|
> denver_co.distance_to(loveland_oh)
|
1322
|
-
=> 1773425.
|
1381
|
+
=> 1773425.54893302 # in meters
|
1323
1382
|
> denver_co.distance_to(loveland_oh).in_miles
|
1324
|
-
=> 1101.
|
1383
|
+
=> 1101.95556640625
|
1384
|
+
|
1385
|
+
# move around the globe using x/y distances in miles or kilometers
|
1325
1386
|
> denver_co.delta_miles(1101.6, -32.556)
|
1326
1387
|
=> #<CLLocationCoordinate2D latitude=39.2681427001953 longitude=-84.2577209472656>
|
1327
|
-
|
1328
|
-
=> 8.0804328918457 # this is in meters
|
1388
|
+
# our location is pretty close!
|
1329
1389
|
> denver_co.delta_miles(1101.6, -32.556).distance_to(loveland_oh).miles
|
1330
|
-
=> 0.
|
1390
|
+
=> 0.90043306350708
|
1391
|
+
|
1392
|
+
> denver_co.delta_kilometers(10, 10) # 10 kilometers east, 10 kilometers north
|
1393
|
+
=> #<CLLocationCoordinate2D latitude=39.8290100097656 longitude=-104.868377685547>
|
1331
1394
|
```
|
1332
1395
|
|
1333
1396
|
Pipes
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class CAAnimation
|
2
|
+
|
3
|
+
class << self
|
4
|
+
|
5
|
+
def basic(target, key_path, options={}, &block)
|
6
|
+
corner_animation = CABasicAnimation.animationWithKeyPath(key_path)
|
7
|
+
corner_animation.duration = options[:duration] if options[:duration]
|
8
|
+
corner_animation.delegate = options[:delegate] if options[:delegate]
|
9
|
+
|
10
|
+
if options.key?(:from) || options.key?(:to) || options.key?(:by)
|
11
|
+
add_animation = options.fetch(:add, true)
|
12
|
+
|
13
|
+
corner_animation.fromValue = options[:from] if options[:from]
|
14
|
+
corner_animation.toValue = options[:to] if options[:to]
|
15
|
+
corner_animation.byValue = options[:by] if options[:by]
|
16
|
+
else
|
17
|
+
add_animation = options.fetch(:add, false)
|
18
|
+
end
|
19
|
+
|
20
|
+
if add_animation
|
21
|
+
target.addAnimation(corner_animation, forKey:key_path)
|
22
|
+
target.send("#{key_path}=", options[:to])
|
23
|
+
end
|
24
|
+
|
25
|
+
block.call(corner_animation) if block
|
26
|
+
return corner_animation
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -5,18 +5,30 @@ class UIView
|
|
5
5
|
# If options is a Numeric, it is used as the duration. Otherwise, duration
|
6
6
|
# is an option, and defaults to 0.3. All the transition methods work this
|
7
7
|
# way.
|
8
|
-
|
8
|
+
# @option options [Float] :duration Animation duration. default: 0.3
|
9
|
+
# @option options [Float] :delay Delay before animations begin. default: 0
|
10
|
+
# @option options [Float] :damping Enables the "spring" animation. Value of 1.0 is a stiff spring.
|
11
|
+
# @option options [Float] :velocity Used in a spring animation to set the initial velocity
|
12
|
+
# @option options [Proc] :after A block that is executed when the animation is complete, useful for chaining (though the `animation_chain` method is better!)
|
13
|
+
# @option options [Fixnum] :options The options parameter that is passed to the UIView.animateWithDuration(...) method. You can also use the more verbose options `:curve`, `:from_current`, and `:allow_interaction`
|
14
|
+
# @option options [Fixnum] :curve The animation curve option. default: UIViewAnimationOptionCurveEaseIn
|
15
|
+
# @option options [Boolean] :from_current Whether or not to have animations start from their current position (aka UIViewAnimationOptionBeginFromCurrentState)
|
16
|
+
# @option options [Boolean] :allow_interaction aka UIViewAnimationOptionAllowUserInteraction
|
17
|
+
def animate(options={}, more_options={}, &animations)
|
9
18
|
raise "animation block is required" unless animations
|
10
19
|
|
11
20
|
if options.is_a? Numeric
|
12
21
|
duration = options
|
13
|
-
options =
|
22
|
+
options = more_options
|
14
23
|
else
|
15
24
|
duration = options[:duration] || 0.3
|
16
25
|
end
|
17
26
|
|
18
27
|
delay = options[:delay] || 0
|
19
28
|
|
29
|
+
damping_ratio = options[:damping] || nil
|
30
|
+
spring_velocity = options[:velocity] || 0.0
|
31
|
+
|
20
32
|
# chain: true is used inside animation_chain blocks to prevent some weird
|
21
33
|
# animation errors (nested animations do not delay/queue as you'd expect)
|
22
34
|
if options[:chain] || Thread.current[:sugarcube_chaining]
|
@@ -47,18 +59,34 @@ class UIView
|
|
47
59
|
animation_options = curve | from_current
|
48
60
|
end
|
49
61
|
|
62
|
+
|
63
|
+
|
64
|
+
|
65
|
+
|
50
66
|
if duration == 0 && delay == 0
|
51
67
|
animations.call
|
52
68
|
after_adjusted.call(true) if after_adjusted
|
53
69
|
else
|
54
70
|
prev_value = Thread.current[:sugarcube_chaining]
|
55
71
|
Thread.current[:sugarcube_chaining] = true
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
72
|
+
|
73
|
+
if damping_ratio
|
74
|
+
UIView.animateWithDuration( duration,
|
75
|
+
delay: delay,
|
76
|
+
usingSpringWithDamping: damping_ratio,
|
77
|
+
initialSpringVelocity: spring_velocity,
|
78
|
+
options: animation_options,
|
79
|
+
animations: animations,
|
80
|
+
completion: after_adjusted
|
81
|
+
)
|
82
|
+
else
|
83
|
+
UIView.animateWithDuration( duration,
|
84
|
+
delay: delay,
|
85
|
+
options: animation_options,
|
86
|
+
animations: animations,
|
87
|
+
completion: after_adjusted
|
88
|
+
)
|
89
|
+
end
|
62
90
|
Thread.current[:sugarcube_chaining] = prev_value
|
63
91
|
end
|
64
92
|
nil
|
@@ -87,12 +115,9 @@ class UIView
|
|
87
115
|
end
|
88
116
|
|
89
117
|
# Same as UIView##animate, but acts on self
|
90
|
-
def animate(options={}, &animations)
|
118
|
+
def animate(options={}, more_options={}, &animations)
|
91
119
|
if options.is_a? Numeric
|
92
|
-
|
93
|
-
options = {}
|
94
|
-
else
|
95
|
-
duration = options[:duration] || 0.3
|
120
|
+
options = more_options.merge(duration: options)
|
96
121
|
end
|
97
122
|
|
98
123
|
assign = options[:assign] || {}
|
@@ -108,7 +133,7 @@ class UIView
|
|
108
133
|
end
|
109
134
|
|
110
135
|
# Changes the layer opacity.
|
111
|
-
def fade(options={}, &after)
|
136
|
+
def fade(options={}, more_options={}, &after)
|
112
137
|
if options.is_a? Numeric
|
113
138
|
options = { opacity: options }
|
114
139
|
end
|
@@ -122,9 +147,9 @@ class UIView
|
|
122
147
|
|
123
148
|
# Changes the layer opacity to 0.
|
124
149
|
# @see #fade
|
125
|
-
def fade_out(options={}, &after)
|
150
|
+
def fade_out(options={}, more_options={}, &after)
|
126
151
|
if options.is_a? Numeric
|
127
|
-
options =
|
152
|
+
options = more_options.merge(duration: options)
|
128
153
|
end
|
129
154
|
|
130
155
|
options[:opacity] ||= 0.0
|
@@ -134,9 +159,9 @@ class UIView
|
|
134
159
|
|
135
160
|
# Changes the layer opacity to 1.
|
136
161
|
# @see #fade
|
137
|
-
def fade_in(options={}, &after)
|
162
|
+
def fade_in(options={}, more_options={}, &after)
|
138
163
|
if options.is_a? Numeric
|
139
|
-
options =
|
164
|
+
options = more_options.merge(duration: options)
|
140
165
|
end
|
141
166
|
|
142
167
|
options[:opacity] ||= 1.0
|
@@ -146,9 +171,9 @@ class UIView
|
|
146
171
|
|
147
172
|
# Changes the layer opacity to 0 and then removes the view from its superview
|
148
173
|
# @see #fade_out
|
149
|
-
def fade_out_and_remove(options={}, &after)
|
174
|
+
def fade_out_and_remove(options={}, more_options={}, &after)
|
150
175
|
if options.is_a? Numeric
|
151
|
-
options =
|
176
|
+
options = more_options.merge(duration: options)
|
152
177
|
end
|
153
178
|
|
154
179
|
original_opacity = self.alpha
|
@@ -162,9 +187,9 @@ class UIView
|
|
162
187
|
fade_out(options, &after_remove)
|
163
188
|
end
|
164
189
|
|
165
|
-
def move_to(position, options={}, &after)
|
190
|
+
def move_to(position, options={}, more_options={}, &after)
|
166
191
|
if options.is_a? Numeric
|
167
|
-
options =
|
192
|
+
options = more_options.merge(duration: options)
|
168
193
|
end
|
169
194
|
|
170
195
|
options[:after] = after
|
@@ -176,18 +201,18 @@ class UIView
|
|
176
201
|
end
|
177
202
|
end
|
178
203
|
|
179
|
-
def delta_to(delta, options={}, &after)
|
204
|
+
def delta_to(delta, options={}, more_options={}, &after)
|
180
205
|
f = self.frame
|
181
206
|
delta = SugarCube::CoreGraphics::Point(delta)
|
182
207
|
position = SugarCube::CoreGraphics::Point(f.origin)
|
183
208
|
to_position = CGPoint.new(position.x + delta.x, position.y + delta.y)
|
184
|
-
move_to(to_position, options, &after)
|
209
|
+
move_to(to_position, options, more_options, &after)
|
185
210
|
self
|
186
211
|
end
|
187
212
|
|
188
|
-
def resize_to(size, options={}, &after)
|
213
|
+
def resize_to(size, options={}, more_options={}, &after)
|
189
214
|
if options.is_a? Numeric
|
190
|
-
options =
|
215
|
+
options = more_options.merge(duration: options)
|
191
216
|
end
|
192
217
|
|
193
218
|
options[:after] = after
|
@@ -199,9 +224,9 @@ class UIView
|
|
199
224
|
end
|
200
225
|
end
|
201
226
|
|
202
|
-
def reframe_to(frame, options={}, &after)
|
227
|
+
def reframe_to(frame, options={}, more_options={}, &after)
|
203
228
|
if options.is_a? Numeric
|
204
|
-
options =
|
229
|
+
options = more_options.merge(duration: options)
|
205
230
|
end
|
206
231
|
|
207
232
|
options[:after] = after
|
@@ -276,10 +301,10 @@ class UIView
|
|
276
301
|
# view.shake(offset: 0.1, repeat: 2, duration: 0.5, keypath: 'transform.rotation')
|
277
302
|
# # slow nodding
|
278
303
|
# view.shake(offset: 20, repeat: 10, duration: 5, keypath: 'transform.translation.y')
|
279
|
-
def shake(options={})
|
304
|
+
def shake(options={}, more_options={})
|
280
305
|
if options.is_a? Numeric
|
281
306
|
duration = options
|
282
|
-
options =
|
307
|
+
options = more_options
|
283
308
|
else
|
284
309
|
duration = options[:duration] || 0.3
|
285
310
|
end
|
@@ -324,10 +349,10 @@ class UIView
|
|
324
349
|
# Moves the view off screen while slowly rotating it.
|
325
350
|
#
|
326
351
|
# Based on https://github.com/warrenm/AHAlertView/blob/master/AHAlertView/AHAlertView.m
|
327
|
-
def tumble(options={}, &after)
|
352
|
+
def tumble(options={}, more_options={}, &after)
|
328
353
|
if options.is_a? Numeric
|
329
354
|
default_duration = options
|
330
|
-
options =
|
355
|
+
options = more_options
|
331
356
|
else
|
332
357
|
default_duration = 0.3
|
333
358
|
end
|
@@ -366,7 +391,7 @@ class UIView
|
|
366
391
|
|
367
392
|
# Moves the view backwards, similar to what Google has been doing a lot
|
368
393
|
# recently
|
369
|
-
def back_fiend!(options={})
|
394
|
+
def back_fiend!(options={}, more_options={})
|
370
395
|
scale = options[:scale] || 0.5
|
371
396
|
perspective = options[:perspective] || -0.0005
|
372
397
|
size = options[:size] || -140
|
@@ -379,7 +404,7 @@ class UIView
|
|
379
404
|
end
|
380
405
|
|
381
406
|
# restores the layer after a call to 'back_fiend!'
|
382
|
-
def forward_fiend!(options={})
|
407
|
+
def forward_fiend!(options={}, more_options={})
|
383
408
|
UIView.animate(options) do
|
384
409
|
self.layer.transform = CATransform3DIdentity
|
385
410
|
end
|
@@ -53,6 +53,9 @@ class NSAttributedString
|
|
53
53
|
foo = NSStrokeWidthAttributeName
|
54
54
|
foo = NSShadowAttributeName
|
55
55
|
foo = NSVerticalGlyphFormAttributeName
|
56
|
+
# new iOS 7 text effects
|
57
|
+
foo = NSTextEffectsAttributeName
|
58
|
+
foo = NSTextEffectsLetterPressStyle
|
56
59
|
# make sure alignments get compiled
|
57
60
|
foo = NSLeftTextAlignment
|
58
61
|
foo = NSRightTextAlignment
|
@@ -130,6 +133,10 @@ class NSAttributedString
|
|
130
133
|
with_attributes({NSVerticalGlyphFormAttributeName => value})
|
131
134
|
end
|
132
135
|
|
136
|
+
def letterpress
|
137
|
+
with_attributes({NSTextEffectsAttributeName => NSTextEffectsLetterPressStyle})
|
138
|
+
end
|
139
|
+
|
133
140
|
def with_attributes(attributes)
|
134
141
|
retval = NSMutableAttributedString.alloc.initWithAttributedString(self)
|
135
142
|
retval.addAttributes(attributes, range:[0, self.length])
|