sugarcube 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile.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])
|