Reputation: 397
I am trying to create a custom knob control that has ticks around its dial. The dial will have a dynamic number of ticks (values), so I'll need to draw them. To start, all I want to do is to create a circle with a number of tick marks around its edge. An example image is above.
Here is where I am at currently (image below), and you can see my math must be quite off, and I'm having difficulty getting it to appear correctly. The angles seem very far apart, the positioning of the ticks should be 1/2 way to the right and 1/2 way down. I tried using a ShapeLayer and moving that, but it didn't seem to do anything. Once I get the drawing correct, I'll make it larger so that it appears like the image at the top (clipped by the screen boundary).
All I really want to do at this point is to draw a dynamic number of tics around the edge of a circle. The angle between them can indeed be fixed too. Thanks for your time and attention.
Here is my custom Class currently.
import UIKit
class Disc: UIView {
// Defaults.
private var myOuterRadius: CGFloat = 100.0
private var myInnerRadius: CGFloat = 90.0
private var myNumberOfTicks: Int = 5
override func draw(_ rect: CGRect)
{
let strokeColor = UIColor.black
let tickPath = UIBezierPath()
for i in 0..<myNumberOfTicks {
let angle = CGFloat(i) * CGFloat(2 * M_PI) / CGFloat(myNumberOfTicks)
let inner = CGPoint(x: myInnerRadius * cos(angle), y: myInnerRadius * sin(angle))
let outer = CGPoint(x: myOuterRadius * cos(angle), y: myOuterRadius * sin(angle))
print(angle, inner, outer)
tickPath.move(to: inner)
tickPath.addLine(to: outer)
}
tickPath.close()
tickPath.lineCapStyle = .round
strokeColor.setStroke()
tickPath.lineWidth = 2
tickPath.stroke()
}
init(width: CGFloat, numTicks: Int)
{
super.init(frame: CGRect(x: 0, y: 0, width: width, height: width))
myOuterRadius = width / 2
myInnerRadius = (width / 2) - 10
myNumberOfTicks = numTicks
self.backgroundColor = UIColor(netHex: 0xEEEEEE)
self.layer.cornerRadius = CGFloat(width / 2)
self.layer.masksToBounds = true
}
required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}
Upvotes: 1
Views: 1580
Reputation: 1378
This would be a good start. There are better ways to draw of course. :p
class ViewController: UIViewController {
var circle: UIView!
override func viewDidLoad() {
super.viewDidLoad()
let diameter = 200.0
let ticks = 100
circle = UIView(frame: CGRect(x: 0, y: 0, width: diameter, height: diameter))
circle.center = view.center
circle.backgroundColor = UIColor.yellow
circle.layer.cornerRadius = 100.0
view.addSubview(circle)
drawTicks(count: ticks)
}
func drawTicks(count: Int) {
let radius = circle.frame.size.width * 0.5
var rotationInDegrees: CGFloat = 0
for i in 0 ..< count {
let tick = createTick()
let x = CGFloat(Float(circle.center.x) + Float(radius) * cosf(2 * Float(i) * Float(M_PI) / Float(count) - Float(M_PI) / 2))
let y = CGFloat(Float(circle.center.y) + Float(radius) * sinf(2 * Float(i) * Float(M_PI) / Float(count) - Float(M_PI) / 2))
tick.center = CGPoint(x: x, y: y)
// degress -> radians
tick.transform = CGAffineTransform.identity.rotated(by: rotationInDegrees * .pi / 180.0)
view.addSubview(tick)
rotationInDegrees = rotationInDegrees + (360.0 / CGFloat(count))
}
}
func createTick() -> UIView {
let tick = UIView(frame: CGRect(x: 0, y: 0, width: 2.0, height: 10.0))
tick.backgroundColor = UIColor.blue
return tick
}
}
Upvotes: 1
Reputation: 8251
As pointed out by vacawama you have to add the position of the circle center to your calculations. You can simply use the center
property of UIView
for that.
let inner = CGPoint(x: myInnerRadius * cos(angle) + center.x,
y: myInnerRadius * sin(angle) + center.y)
let outer = CGPoint(x: myOuterRadius * cos(angle) + center.x,
y: myOuterRadius * sin(angle) + center.y)
Upvotes: 1
Reputation: 154583
Your problem is that you are using (0, 0)
as the center of your circle.
You need to establish values for the center point of your circle, and then add those offsets to the endpoints of your tick marks.
let centerX: CGFloat = myOuterRadius
let centerY: CGFloat = myOuterRadius
Then use those values when computing inner
and outer
:
let inner = CGPoint(x: myInnerRadius * cos(angle) + centerX,
y: myInnerRadius * sin(angle) + centerY)
let outer = CGPoint(x: myOuterRadius * cos(angle) + centerX,
y: myOuterRadius * sin(angle) + centerY)
Upvotes: 1