Frage

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 show the drawing again.

War es hilfreich?

Lösung

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;

Andere Tipps

/// 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
}

/// 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!

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top