powing
(Albert)
1
Apple's Interface Guidelines suggest a Pan gesture over a Swipe if seeking to "track the movement of the user’s fingers onscreen ... use a pan gesture recognizer to drag objects around in your interface or update their appearance".
Drawing shapes I am looking to use the Pan gesture to increase or decrease the number of sides of a shape e.g. a hexagon (six sides) to a circle (infinite sides), of which the onscreen shapes should update in real time:
override func draw(_ rect: CGRect) {
let path = UIBezierPath()
let radius: Double = Double(rect.width) / 2 - 20
let centre = CGPoint(x: rect.width / 2, y: rect.height / 3)
path.move(to: CGPoint(x: centre.x + CGFloat(radius), y: centre.y))
for i in stride(from: 0, to: 361.0, by: 45) {
let radians = i * Double.pi / 180
let x = Double(centre.x) + radius * cos(radians)
let y = Double(centre.y) + radius * sin(radians)
path.addLine(to: CGPoint(x: x, y: y))
}
path.stroke()
}
I was thinking of using UIPanGestureRecognizer to generate a number for the Stride "by" value which would alter the shape on screen:
func panningRange(_ sender: UIPanGestureRecognizer) {
if sender.state == .began || sender.state == .changed {
pan = sender.location(in: circleGenerator).y
setNeedsDisplay()
}
}
Issues remain however:
-
Anything more than 45 and the shape drawn won't connect its lines (this is why the "to" value is 361.0)
-
With a pinch gesture example a print statement showed float numbers with fourteen decimal places, I can round these up as integers to mimic a slider bar, but they are only single digits like "1" (a circle). I need the shapes to change within a short distance of movement (even on a smaller iPhone SE screen), so I will likely need to modify the counter logic to get higher integers e.g. 25, 30..
-
It will be necessary to round up generated numbers to known values that will produce recognisable shapes e.g. 45 = nonagon (9 sided shape), otherwise the shapes can look unflattering during transition
-
Transitioning smoothly between recognisable shapes should be smooth and immediate, I don't know if the UIBezierPath logic I have will be the optimal choice for what I am trying to achieve?
-
Is a Pan gesture the right option to avoid a visible sliding UI bar?
361, unlike 360, works because stride returns a sequence from a starting value to, but not including, an end value. Also, it's always a good idea to close() the path once you're done drawing. You can do it instead of drawing the last side to ensure a clean connection:
...
let angle = (2 * .pi) / Double(numberOfSides)
for i in 1..<numberOfSides {
let radians = angle * Double(i)
let x = Double(centre.x) + radius * cos(radians)
let y = Double(centre.y) + radius * sin(radians)
path.addLine(to: CGPoint(x: x, y: y))
}
path.close()
path.stroke()
UIBezierPath is a great choice. You can also draw using the methods on CGContext, there is no particular difference.
100 points is more than enough to transition from a triangle to a polygon that is visually indistinguishable from a circle. An iPhone SE screen should be at least 300 points wide.
In terms of gestures, It certainly is the most suitable one.