简体   繁体   English

UIBezierPath 围绕 UIView 的中心旋转

[英]UIBezierPath Rotation around a UIView's center

I'm creating a custom UIView , in which I implement its draw(rect:) method by drawing a circle with a large width using UIBezierPath, that draw a square on the top (as shown in the picture, don't consider the colors or the size).我正在创建一个自定义UIView ,其中我通过使用 UIBezierPath 绘制一个大宽度的圆来实现它的draw(rect:)方法,在顶部绘制一个正方形(如图所示,不考虑颜色或大小)。 Then I try creating rotated copies of the square, to match a "settings" icon (picture 2, consider only the outer ring).然后我尝试创建正方形的旋转副本,以匹配“设置”图标(图 2,仅考虑外环)。 To do that last thing, I need to rotate the square using a CGAffineTransform(rotationAngle:) but the problem is that this rotation's center is the origin of the frame, and not the center of the circle.要做最后一件事,我需要使用CGAffineTransform(rotationAngle:)旋转正方形,但问题是这个旋转的中心是框架的原点,而不是圆的中心。 How can I create a rotation around a certain point in my view?如何在我的视图中围绕某个点创建旋转?

图片1

图 2

As a demonstration of @DuncanC's answer (up voted), here is the drawing of a gear using CGAffineTransform s to rotate the gear tooth around the center of the circle:作为@DuncanC 答案的演示(投票赞成),这是使用CGAffineTransform围绕圆心旋转齿轮齿的齿轮图:

class Gear: UIView {
    var lineWidth: CGFloat = 16
    let boxWidth: CGFloat = 20
    let toothAngle: CGFloat = 45

    override func draw(_ rect: CGRect) {

        let radius = (min(bounds.width, bounds.height) - lineWidth) / 4.0

        var path = UIBezierPath()
        path.lineWidth = lineWidth
        UIColor.white.set()

        // Use the center of the bounds not the center of the frame to ensure
        // this draws correctly no matter the location of the view
        // (thanks @dulgan for pointing this out)
        let center = CGPoint(x: bounds.maxX / 2, y: bounds.maxY / 2)

        // Draw circle
        path.move(to: CGPoint(x: center.x + radius, y: center.y))
        path.addArc(withCenter: CGPoint(x: center.x, y: center.y), radius: radius, startAngle: 0, endAngle: 2 * .pi, clockwise: true)
        path.stroke()

        // Box for gear tooth
        path = UIBezierPath()
        let point = CGPoint(x: center.x - boxWidth / 2.0, y: center.y - radius)
        path.move(to: point)
        path.addLine(to: CGPoint(x: point.x, y: point.y - boxWidth))
        path.addLine(to: CGPoint(x: point.x + boxWidth, y: point.y - boxWidth))
        path.addLine(to: CGPoint(x: point.x + boxWidth, y: point.y))
        path.close()
        UIColor.red.set()

        // Draw a tooth every toothAngle degrees
        for _ in stride(from: toothAngle, through: 360, by: toothAngle) {
            // Move origin to center of the circle
            path.apply(CGAffineTransform(translationX: -center.x, y: -center.y))

            // Rotate
            path.apply(CGAffineTransform(rotationAngle: toothAngle * .pi / 180))

            // Move origin back to original location
            path.apply(CGAffineTransform(translationX: center.x, y: center.y))

            // Draw the tooth
            path.fill()
        }
    }
}

let view = Gear(frame: CGRect(x: 0, y: 0, width: 200, height: 200))

Here it is running in a Playground:它在 Playground 中运行:

在操场上运行的齿轮演示

Shift the origin of your transform, Rotate, Shift back移动变换的原点,旋转,移回

Apply your transform应用您的转换

If you want a quick n dirty version using UIViews instead:如果您想要使用 UIViews 的快速 n 脏版本:

UIView * dialView = [UIView new];
dialView.frame = CGRectMake(0, localY, w, 300);
dialView.backgroundColor = [UIColor whiteColor];
[analyticsView addSubview:dialView];

float lineWidth = 6;
float lineHeight = 20.0f;
int numberOfLines = 36;
for (int n = 0; n < numberOfLines; n++){

    UIView * lineView = [UIView new];
    lineView.frame = CGRectMake((w-lineWidth)/2, (300-lineHeight)/2, lineHeight, lineWidth);
    lineView.backgroundColor = [UIColor redColor];
    [dialView addSubview:lineView];

    lineView.transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(360/numberOfLines*n));
    lineView.transform = CGAffineTransformTranslate(lineView.transform, (150-lineHeight), 0);

}

Giving:给予:

在此处输入图片说明

Where w is a holder width, and radians are calculated by:其中w是支架宽度,弧度计算如下:

#define DEGREES_TO_RADIANS(degrees)((M_PI * degrees)/180)

Maybe would help someone.也许会帮助某人。 Source资源

extension UIBezierPath {
    func rotate(degree: CGFloat) {
        let bounds: CGRect = self.cgPath.boundingBox
        let center = CGPoint(x: bounds.midX, y: bounds.midY)

        let radians = degree / 180.0 * .pi
        var transform: CGAffineTransform = .identity
        transform = transform.translatedBy(x: center.x, y: center.y)
        transform = transform.rotated(by: radians)
        transform = transform.translatedBy(x: -center.x, y: -center.y)
        self.apply(transform)
    }
}

Example:例子:

let progressLayerPath = UIBezierPath(ovalIn: CGRect(x: 0,
                                                    y: 0,
                                                    width: 70,
                                                    height: 70))
progressLayerPath.rotate(degree: -90) // <-------
progressLayer.path = progressLayerPath.cgPath
progressLayer.strokeColor = progressColor.cgColor
progressLayer.fillColor = UIColor.clear.cgColor
progressLayer.lineWidth = lineWidth
layer.addSublayer(progressLayer)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM