Is it possible to reposition an already drawn CGPath/UIBezierPath on a view? I would like to move or change a path\'s position then perhaps recall the drawinRect method to just
/// Provide cgpath to it and tanslate it by given point.
func translate(path : CGPath?, by point: CGPoint) -> CGPath? {
let bezeirPath = UIBezierPath()
guard let prevPath = path else {
return nil
}
bezeirPath.cgPath = prevPath
bezeirPath.apply(CGAffineTransform(translationX: point.x, y: point.y))
return bezeirPath.cgPath
}
I did it a bit different from other answers above.
Let's suppose you want to move a circle, first I define its center coordinates and radius in global variables, like this:
var center: CGPoint = CGPoint(x: UIScreen.main.bounds.width/2, y: UIScreen.main.bounds.height/2)
var radius: CGFloat = 10
I draw this circle like in the code bellow:
override func draw(_ rect: CGRect) {
super.draw(rect)
drawCircle()
}
func drawCircle() {
let circle = UIBezierPath(
arcCenter: self.center,
radius: CGFloat(self.radius),
startAngle: CGFloat(0),
endAngle: CGFloat(2*Double.pi),
clockwise: true)
let circleLayer = CAShapeLayer()
circleLayer.path = circle.cgPath
circleLayer.fillColor = UIColor.clear.cgColor
circleLayer.strokeColor = UIColor.black.cgColor
circleLayer.lineWidth = 10.0
layer.addSublayer(circleLayer)
}
Inside the UIView, I have a touchesMoved(), like this:
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?){
if let touch = touches.first {
let pos = touch.location(in: self)
if (pow(pos.x-self.center.x,2) + pow(pos.y-self.center.y,2) <= pow(self.radius,2)){
self.center = CGPoint(x: pos.x, y: pos.y)
}
setNeedsDisplay()
}
}
Everytime the touch is inside the circle, its center coordinates are updated and the UIView is redrawn with setNeedDisplay()
, so the circle moves.
Hope it helps someone!
/// Translate cgPath from its center to give point.No need to move shape layer .Moving path will make app smooth
func translate(path : CGPath?, by point: CGPoint) -> CGPath? {
let bezeirPath = UIBezierPath()
guard let prevPath = path else {
return nil
}
bezeirPath.cgPath = prevPath
bezeirPath.apply(CGAffineTransform(translationX: point.x, y: point.y))
return bezeirPath.cgPath
}
From your question it sounds like you are drawing the path using Core Graphics inside drawRect:
(as compared to using a CAShapeLayer
) so I'll explain the version first.
You can create a new path by transforming another path. A translation transform moves the transformed object a certain distance in x and y. So using a translation transform you can move your existing path a certain number of points in both x and y.
CGAffineTransform translation = CGAffineTransformMakeTranslation(xPixelsToMove,
yPixelsToMove);
CGPathRef movedPath = CGPathCreateCopyByTransformingPath(originalCGPath,
&translation);
Then you could use the movedPath
to draw the same way you are already doing.
You could also change modify the same path
yourPath = CGPathCreateCopyByTransformingPath(yourPath,
&translation);
and simply redraw it.
If you are using a shape layer, moving it is even easier. Then you only have to change the position of the layer using the position
property.
If you want to use a shape layer you can simply create a new CAShapeLayer and set its path to be your CGPath. You will need QuartzCore.framework for this since CAShapeLayer is part of Core Animation.
CAShapeLayer *shape = [CAShapeLayer layer];
shape.path = yourCGParth;
shape.fillColor = [UIColor redColor].CGColor;
[someView.layer addSublayer:shape];
Then to move the shape you simply change its position.
shape.position = thePointYouWantToMoveTheShapeTo;