How can I update position of an already drawn CGPath
/UIBezierPath
on a view? I would like to move or change a path's position and then perhaps call the drawInRect
method to just render the path again.

- 2,150
- 2
- 23
- 30

- 2,982
- 10
- 43
- 72
-
What are they drawn on? The views layer? A sub layer? A shape layer? – Wain Jun 18 '13 at 12:36
-
They are being drawn on a views layer. – SleepNot Jun 19 '13 at 02:27
3 Answers
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.
Moving a CGPath
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.
Moving a shape layer
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.
Update:
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;

- 1
- 1

- 56,267
- 18
- 167
- 205
-
I tried the first code you suggested CGAffineTransformMakeTranslation but with the current x and y of my touch as the parameters. It doesnt seem to be following the touch location and is kinda incrementing the position of the path. – SleepNot Jun 19 '13 at 03:34
-
@jeraldov You should pass in the difference in x and y. For example the `translationInView:` for a pan gesture recognizer. That said, if you are going to move the shape a lot you should consider a shape layer. – David Rönnqvist Jun 19 '13 at 05:19
-
Yes I'll be moving the shape a lot since I want to drag/move a shape on TouchesMoved event. I will try to go with the shape layer route. Can you give me a sample or a tutorial on how to do shape layers? Thanks. – SleepNot Jun 19 '13 at 06:17
-
@jeraldov I've updated my question. Does it explain enough about shape layers? – David Rönnqvist Jun 19 '13 at 07:24
-
-
Hi. I run into some problem again, it seems like if I change the position of the shape, it doesnt appear on the view. How do I update the position of the view and make the change visible. – SleepNot Jun 21 '13 at 03:34
-
Hello @DavidRönnqvist, can this logic be used for undo/redo like when we do undo, move the path out of the screen and when we do redo bring back to its initial position. Not sure just a thought – Ranjit Feb 01 '14 at 13:07
-
@Ranjit in theory it could but creating a new copy of the path and just moving it off screen for every step that can be undone/redone could introduce performance problems, so it's best to prototype and measure first. – David Rönnqvist Feb 01 '14 at 13:24
-
ok @DavidRönnqvist, could be please look at this http://stackoverflow.com/questions/21438586/undo-redo-for-drawing-in-ios, I am totally stuck with it – Ranjit Feb 01 '14 at 13:26
-
could you show your implementation in `Swift` too? I am confused about `&translation` expression – János Oct 26 '14 at 00:03
-
The translated path has incorrect bounds, lets say I moved a layer from point(0.0) to point(100, 100), but when I print the boundingbox of cgpath its some where around point(150, 200). any idea whats the issue. – Raj Kiran Sep 01 '21 at 23:16
/// 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
}

- 668
- 6
- 14
-
The translated path has incorrect bounds, lets say I moved a layer from point(0.0) to point(100, 100), but when I print the boundingbox of cgpath its some where around point(150, 200). any idea whats the issue. – Raj Kiran Sep 01 '21 at 23:16
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!

- 345
- 1
- 2
- 13