Drag the circles around the screen and place them on top of each other. Only the circle objects, not the big white object in the background, are touch-sensitive. And not all of each circle object is touch-sensitve. Only the region within the circumference is.
The class
Circle
in this app is a subclass of class
UIView
and is therefore rectangular.
A
Circle
is in fact a perfect square,
but you don’t see the square.
All you see is the circle drawn on it,
with a radius equal to half the length of a side of the square.
Until now, a touch-sensitive
UIView
has been touch-sensitive over its entire area.
But a
Circle
is touch-sensitive only on or within the circumference of its circle.
The four corners of the
Circle
outside the circumference are touch-insensitive,
and are
clear
in color.
See the
pointInside(_:withEvent:)
method of class
UIView
,
and
Hit
Testing.
The touched
Circle
brings itself to the front,
i.e., it is placed on top of the other circles.
See the
bringSubviewToFront:
method of class
UIView
.
A
touch
object
passed to
touchesMoved(_:withEvent:)
has a
previous
location
as well as a
current
location.
The
hypot
function returns the distance from a given point to the origin
using the
Pythagrean
theorem,
and the origin of a
Circle
object is at the center of its circle.
When the
init(decoder:)
method of the app’s
View
object
(or biggest
UIView
object)
is called automatically by the app’s
Main.storyboard
file,
the
View
is given a dummy size of 600 × 600 pairs of pixels.
That’s why the
init(decoder:)
of this
View
does not attempt to give a size and position to the subviews.
At some later time,
the size of this
View
is changed to the correct value (the size of the screen).
When that happens,
the
View
’s
layoutSubviews
method is called.
AppDelegate
ViewController
.
View
:
the white background.
Circle
:
a movable circle.
Calls
pointInside(_:withEvent:)
and
bringSubviewToFront(_:)
.
Circle
properties of class
View
into a single property that is an
array
of three
Circle
s.
Remove the three existing
Circle
properties and replace them by
the following.
let colors: [UIColor] = [ UIColor.greenColor(), UIColor.cyanColor(), UIColor.blueColor() ]; let circles: [Circle] = [Circle](); //Create an empty array of Circles.In the
init(decoder:)
method of the
View
,
create the circles and addSubview them with a
for-in
loop.
for color in colors { let circle: Circle = Circle(color: color); circles.append(circle); addSubview(circle); }In the
layoutSubviews
method of the
View
,
read the sizes and positions of the
Circle
s
from an
array
of
tuples.
let tuples: [(center: CGPoint, radius: CGFloat)] = [ (CGPointMake(x, y + size.height / 4), size.width / 10), (CGPointMake(x, y + size.height / 2), size.width / 8), (CGPointMake(x, y + size.height * 5 / 8), size.width / 5) ]; for var i = 0; i < circles.count; ++i { circles[i].center = tuples[i].center; circles[i].radius = tuples[i].radius; }
Circle
contains the code to detect a touch and update the
center
property of each
Circle
.
All of this could be done in class
View
instead.
See the
hitTest(_:withEvent:)
method of class
UIView
in
Puzzle.