在iOS中创建六边形ImageView形状

14
我想要一个六边形的形状作为我的ImageView。但是在实现下面的代码后,我得到了这个图像。
- (UIBezierPath *)roundedPolygonPathWithRect:(CGRect)square
                                    lineWidth:(CGFloat)lineWidth
                                        sides:(NSInteger)sides
                                cornerRadius:(CGFloat)cornerRadius
{
    UIBezierPath *path  = [UIBezierPath bezierPath];

    CGFloat theta       = 2.0 * M_PI / sides;                           // how much to turn at every corner
    CGFloat offset      = cornerRadius * tanf(theta / 2.0);             // offset from which to start rounding corners
    CGFloat squareWidth = MIN(square.size.width, square.size.height);   // width of the square

    // calculate the length of the sides of the polygon

    CGFloat length      = squareWidth - lineWidth;
    if (sides % 4 != 0) {                                               // if not dealing with polygon which will be square with all sides ...
        length = length * cosf(theta / 2.0) + offset/2.0;               //     ... offset it inside a circle inside the square
    }
    CGFloat sideLength = length * tanf(theta / 2.0);

    // start drawing at `point` in lower right corner

    CGFloat calc = squareWidth / 2.0 + sideLength / 2.0 - offset;

    CGPoint point = CGPointMake(calc, squareWidth - (squareWidth - length) / 2.0);
    CGFloat angle = M_PI;
    [path moveToPoint:point];

    // draw the sides and rounded corners of the polygon

    for (NSInteger side = 0; side < sides; side++)
    {
        point = CGPointMake(point.x + (sideLength - offset * 2.0) * cosf(angle), point.y + (sideLength - offset * 2.0) * sinf(angle));
        [path addLineToPoint:point];

        CGPoint center = CGPointMake(point.x + cornerRadius * cosf(angle + M_PI_2), point.y + cornerRadius * sinf(angle + M_PI_2));
        [path addArcWithCenter:center radius:cornerRadius startAngle:angle - M_PI_2 endAngle:angle + theta - M_PI_2 clockwise:YES];

        point = path.currentPoint; // we don't have to calculate where the arc ended ... UIBezierPath did that for us
        angle += theta;
    }

    [path closePath];

    return path;
}


 CGFloat lineWidth    = 5.0;
     UIBezierPath *path   = [self roundedPolygonPathWithRect:cell.eventImageView.bounds
                                              lineWidth:lineWidth
                                                  sides:6
                                           cornerRadius:10];

     CAShapeLayer *mask   = [CAShapeLayer layer];
     mask.path            = path.CGPath;
     mask.lineWidth       = lineWidth;
     mask.strokeColor     = [UIColor clearColor].CGColor;
     mask.fillColor       = [UIColor whiteColor].CGColor;
     cell.eventImageView.layer.mask = mask;

     CAShapeLayer *border = [CAShapeLayer layer];
     border.path          = path.CGPath;
     border.lineWidth     = lineWidth;
     border.strokeColor   = [UIColor blackColor].CGColor;
     border.fillColor     = [UIColor clearColor].CGColor;
     [cell.eventImageView.layer addSublayer:border];

请帮忙告诉我如何实现这个功能,我从未使用过贝塞尔曲线路径。

谢谢!


2
更新你的问题,并附上你所做的内容。 - rmaddy
1
刚刚编辑了这个问题。 - Gaurav Singla
2
所以您基本上想要整个东西旋转30度?或者还有其他问题让您不满意吗? - luk2302
1
不不不,我只是想知道除了旋转之外,生成的图像是否正常,或者是否还有其他问题... - luk2302
1
@luk2302 我尝试对整个图像进行旋转,现在形状很完美,但是图像被旋转了。之后我还尝试仅旋转贝塞尔路径,以便我们只旋转形状而不是整个图像,但它没有起作用。这是代码:CGAffineTransform transform = CGAffineTransformMakeRotation(M_PI / 2); [path applyTransform:transform]; [path fill]; - Gaurav Singla
显示剩余2条评论
3个回答

17

我将Swift中的路径创建函数进行了重构,现在它还可以接受rotationOffset参数,允许对正多边形进行任意旋转。

我不完全确定我的函数与您的函数是否等效(因为我使用极坐标绘制多边形),但生成的结果看起来很像您想要的样子。

public func roundedPolygonPath(rect: CGRect, lineWidth: CGFloat, sides: NSInteger, cornerRadius: CGFloat, rotationOffset: CGFloat = 0) -> UIBezierPath {
    let path = UIBezierPath()
    let theta: CGFloat = CGFloat(2.0 * M_PI) / CGFloat(sides) // How much to turn at every corner
    let offset: CGFloat = cornerRadius * tan(theta / 2.0)     // Offset from which to start rounding corners
    let width = min(rect.size.width, rect.size.height)        // Width of the square

    let center = CGPoint(x: rect.origin.x + width / 2.0, y: rect.origin.y + width / 2.0)

    // Radius of the circle that encircles the polygon
    // Notice that the radius is adjusted for the corners, that way the largest outer
    // dimension of the resulting shape is always exactly the width - linewidth
    let radius = (width - lineWidth + cornerRadius - (cos(theta) * cornerRadius)) / 2.0

    // Start drawing at a point, which by default is at the right hand edge
    // but can be offset
    var angle = CGFloat(rotationOffset)

    let corner = CGPointMake(center.x + (radius - cornerRadius) * cos(angle), center.y + (radius - cornerRadius) * sin(angle))
    path.moveToPoint(CGPointMake(corner.x + cornerRadius * cos(angle + theta), corner.y + cornerRadius * sin(angle + theta)))

    for _ in 0..<sides {
        angle += theta

        let corner = CGPointMake(center.x + (radius - cornerRadius) * cos(angle), center.y + (radius - cornerRadius) * sin(angle))
        let tip = CGPointMake(center.x + radius * cos(angle), center.y + radius * sin(angle))
        let start = CGPointMake(corner.x + cornerRadius * cos(angle - theta), corner.y + cornerRadius * sin(angle - theta))
        let end = CGPointMake(corner.x + cornerRadius * cos(angle + theta), corner.y + cornerRadius * sin(angle + theta))

        path.addLineToPoint(start)
        path.addQuadCurveToPoint(end, controlPoint: tip)
    }

    path.closePath()

    // Move the path to the correct origins
    let bounds = path.bounds
    let transform = CGAffineTransformMakeTranslation(-bounds.origin.x + rect.origin.x + lineWidth / 2.0, -bounds.origin.y + rect.origin.y + lineWidth / 2.0)
    path.applyTransform(transform)

    return path
}
例如,当将 rotationOffset 设置为 M_PI / 6.0 时,生成的形状将类似于以下内容:Resulting polygon with M_PI / 6.0 rotation
如果需要,您可以在此处查看我使用的完整 playground,链接在此处
更新(2018年3月14日):已使用 Swift 4 语法更新了这个 gist,可以在此处查看。

有没有办法将这段代码用作UIImage的扩展?我不太理解您是如何创建六边形的,但如果您能帮忙,我真的很感激。 :) - Ximena Flores de la Tijera

10

这是我在 Objective-C 中使用的代码。我只是根据 Henri 的答案进行了编辑,并且它完美地工作了。感谢你,老兄!

 - (UIBezierPath *)roundedPolygonPathWithRect:(CGRect)rect
                               lineWidth:(CGFloat)lineWidth
                                   sides:(NSInteger)sides
                            cornerRadius:(CGFloat)cornerRadius
{
    UIBezierPath *path  = [UIBezierPath bezierPath];

    CGFloat theta       = 2.0 * M_PI / sides;                           // how much to turn at every corner
    CGFloat offset      = cornerRadius * tanf(theta / 2.0);             // offset from which to start rounding corners
    CGFloat width = MIN(rect.size.width, rect.size.height);   // width of the square

    // Calculate Center
    CGPoint center = CGPointMake(rect.origin.x + width / 2.0, rect.origin.y + width / 2.0);
    CGFloat radius = (width - lineWidth + cornerRadius - (cos(theta) * cornerRadius)) / 2.0;

    // Start drawing at a point, which by default is at the right hand edge
    // but can be offset
    CGFloat angle = M_PI / 2;

    CGPoint corner = CGPointMake(center.x + (radius - cornerRadius) * cos(angle), center.y + (radius - cornerRadius) * sin(angle));
    [path moveToPoint:(CGPointMake(corner.x + cornerRadius * cos(angle + theta), corner.y + cornerRadius * sin(angle + theta)))];

    // draw the sides and rounded corners of the polygon

    for (NSInteger side = 0; side < sides; side++)
    {

        angle += theta;

        CGPoint corner = CGPointMake(center.x + (radius - cornerRadius) * cos(angle), center.y + (radius - cornerRadius) * sin(angle));
        CGPoint tip = CGPointMake(center.x + radius * cos(angle), center.y + radius * sin(angle));
        CGPoint start = CGPointMake(corner.x + cornerRadius * cos(angle - theta), corner.y + cornerRadius * sin(angle - theta));
        CGPoint end = CGPointMake(corner.x + cornerRadius * cos(angle + theta), corner.y + cornerRadius * sin(angle + theta));

        [path addLineToPoint:start];
        [path addQuadCurveToPoint:end controlPoint:tip];
    }

    [path closePath];

    CGRect bounds = path.bounds;
    CGAffineTransform transform =  CGAffineTransformMakeTranslation(-bounds.origin.x + rect.origin.x + lineWidth / 2.0, -bounds.origin.y + rect.origin.y + lineWidth / 2.0);
    [path applyTransform:transform];

    return path;
}

1

这是用CGPath绘制的代码

- (CGPathRef)roundedPolygonPathWithRect:(CGRect)rect lineWidth:(CGFloat)lineWidth sides:(NSInteger)sides cornerRadius:(CGFloat)cornerRadius {

/*
//Center your poligon, depends from reference system
rect = CGRectMake(rect.origin.x - (rect.size.width - lineWidth)/2.0,
                  rect.origin.y - (rect.size.height - lineWidth)/2.0,
                  rect.size.width,
                  rect.size.height);
 */

CGMutablePathRef pathRef  = CGPathCreateMutable();

CGFloat theta       = 2.0 * M_PI / sides;                           // how much to turn at every corner
//CGFloat offset      = cornerRadius * tanf(theta / 2.0);             // offset from which to start rounding corners
CGFloat width = MIN(rect.size.width, rect.size.height);   // width of the square

// Calculate Center
CGPoint center = CGPointMake(rect.origin.x + width / 2.0, rect.origin.y + width / 2.0);
CGFloat radius = (width - lineWidth + cornerRadius - (cos(theta) * cornerRadius)) / 2.0;

// Start drawing at a point, which by default is at the right hand edge
// but can be offset
CGFloat angle = M_PI / 2;

CGPoint corner = CGPointMake(center.x + (radius - cornerRadius) * cos(angle), center.y + (radius - cornerRadius) * sin(angle));
CGPathMoveToPoint(pathRef, nil, corner.x + cornerRadius * cos(angle + theta), corner.y + cornerRadius * sin(angle + theta));

// draw the sides and rounded corners of the polygon
for (NSInteger side = 0; side < sides; side++) {

    angle += theta;

    CGPoint corner = CGPointMake(center.x + (radius - cornerRadius) * cos(angle), center.y + (radius - cornerRadius) * sin(angle));
    CGPoint tip = CGPointMake(center.x + radius * cos(angle), center.y + radius * sin(angle));
    CGPoint start = CGPointMake(corner.x + cornerRadius * cos(angle - theta), corner.y + cornerRadius * sin(angle - theta));
    CGPoint end = CGPointMake(corner.x + cornerRadius * cos(angle + theta), corner.y + cornerRadius * sin(angle + theta));

    //[path addLineToPoint:start];
    CGPathAddLineToPoint(pathRef, nil, start.x, start.y);

    //[path addQuadCurveToPoint:end controlPoint:tip];
    CGPathAddQuadCurveToPoint(pathRef, nil, tip.x, tip.y, end.x, end.y);
}

CGPathCloseSubpath(pathRef);

return pathRef;

}


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