在视图中重新定位CGPath/UIBezierPath

13

如何在视图上更新已绘制的CGPath/UIBezierPath的位置?我想移动或更改路径的位置,然后可能调用drawInRect方法来重新渲染路径。


它们是画在哪里的?视图层?子层?形状层? - Wain
它们正在视图层上绘制。 - SleepNot
4个回答

25

根据您的问题,看起来您正在使用Core Graphics在drawRect:内绘制路径(与使用CAShapeLayer相比),因此我将首先解释这个版本。

移动CGPath

您可以通过转换另一个路径来创建新路径。 平移变换将变换对象沿x和y移动一定距离。 因此,使用平移变换,您可以将现有路径在x和y方向上移动一定数量的点。

CGAffineTransform translation = CGAffineTransformMakeTranslation(xPixelsToMove,
                                                                 yPixelsToMove);
CGPathRef movedPath = CGPathCreateCopyByTransformingPath(originalCGPath,
                                                         &translation);

然后,您可以使用movedPath以与您已经执行的方式相同的方式进行绘制。

您还可以更改修改相同的路径。

yourPath = CGPathCreateCopyByTransformingPath(yourPath,
                                              &translation);

然后简单地重新绘制它。

移动形状图层

如果您正在使用形状图层,则移动它会更容易。然后,您只需要使用position属性更改图层的位置即可。

更新:

如果您想要使用形状图层,您可以简单地创建一个新的CAShapeLayer,并将其路径设置为您的CGPath。由于CAShapeLayer是核心动画的一部分,因此您需要QuartzCore.framework。

CAShapeLayer *shape = [CAShapeLayer layer];
shape.path = yourCGParth;
shape.fillColor = [UIColor redColor].CGColor;

[someView.layer addSublayer:shape];

然后,要移动形状,只需更改其位置即可。

shape.position = thePointYouWantToMoveTheShapeTo;

我尝试了你建议的第一个代码 CGAffineTransformMakeTranslation,但是使用当前触摸的x和y作为参数。它似乎没有跟随触摸位置,并且有点增加路径的位置。 - SleepNot
@jeraldov 我更新了我的问题。它是否足够解释形状图层? - David Rönnqvist
是的,它可以。我现在能够重新定位我的绘图。 - SleepNot
你好@DavidRönnqvist,这个逻辑可以用于撤销/重做吗?比如当我们执行撤销操作时,将路径移出屏幕,当我们执行重做操作时,将其带回初始位置。不确定,只是一个想法。 - Ranjit
好的@DavidRönnqvist,能否请您看一下这个链接https://dev59.com/0Hvaa4cB1Zd3GeqPI-Sr,我完全卡住了。 - Ranjit
显示剩余6条评论

8

将cgPath从中心点移动到指定点,无需移动形状层。移动路径会使应用程序更加流畅。

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
}

翻译后的路径具有不正确的边界,比如我将一个图层从点(0.0)移动到点(100, 100),但是当我打印cgpath的boundingbox时,它在某个地方大约是在点(150, 200)。你知道问题出在哪里吗? - Raj Kiran

1

/// 提供cgpath并通过给定的点进行平移。

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
}

0

我与其他上面的答案有所不同。

假设您要移动一个圆,首先我将其中心坐标和半径定义为全局变量,像这样:

var center: CGPoint = CGPoint(x: UIScreen.main.bounds.width/2, y: UIScreen.main.bounds.height/2)
var radius: CGFloat = 10

我像下面的代码一样画了这个圆形:

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

在UIView内部,我有一个touchesMoved()方法,就像这样:

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()
    }
}

每次触摸在圆形内部时,其中心坐标会更新,并使用setNeedDisplay()重新绘制UIView,因此圆形会移动。
希望能对某人有所帮助!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接