在 iOS 中创建六边形 ImageView 形状
Create Hexagon ImageView shape in iOS
我想要 ImageView 的 Above Hexagon 形状。但是在执行了下面的代码之后,我得到了这张图片
- (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];
请帮助我如何实现它,我以前从未使用过贝塞尔路径。
提前致谢!
我重构了 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
,生成的形状将如下所示
为了以防万一,你可以看看我用的完整游乐场here
更新(2018 年 3 月 14 日):
更新了Swift 4语法的要点,可见here.
这是我在 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;
}
这是使用 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;
}
- (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];
请帮助我如何实现它,我以前从未使用过贝塞尔路径。
提前致谢!
我重构了 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
,生成的形状将如下所示
为了以防万一,你可以看看我用的完整游乐场here
更新(2018 年 3 月 14 日): 更新了Swift 4语法的要点,可见here.
这是我在 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;
}
这是使用 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;
}