复杂图像(气泡/图钉)和[UIImage resizableImageWithCapInsets:]

时间:2016-08-10 14:09:28

标签: ios objective-c iphone uiimage

我正在尝试创建以下图片的可调整大小的版本(40x28,底部的小三角应该水平居中):

enter image description here

UIEdgeInsets imageInsets = UIEdgeInsetsMake(4.0f, 4.0f, 8.0f, 4.0f);
UIImage *pinImage = [[UIImage imageNamed:@"map_pin"] resizableImageWithCapInsets:imageInsets];                                                                       

根据documentation,这个简单的方法不起作用,因为我的三角形落入可调整大小的区域(固定高度但可扩展的宽度):

enter image description here

这将导致与this非常相似的SO后复制(平铺)三角形中描述的相同问题。但不幸的是,他们的解决方案对我的特定情况不起作用,因为从可缩放区域中排除三角形会导致其错位,并且由于明显的原因它不会水平居中。

所以我想知道......是否有可能使用[UIImage resizableImageWithCapInsets:]方法实现我的目标?或者我应该尝试其他一些东西,比如在代码中绘制所有内容?

基本上,我想从Google Maps SDK中实现类似Info Windows的内容:

enter image description here

2 个答案:

答案 0 :(得分:1)

您可以使用UIBezierPath来实现这一点。以下代码在swift中,但您应该能够在Objective-C中实现相同的功能

而不是用直线启动代码:

path.moveToPoint(CGPoint(x: 300, y: 0))

我改为以弧形(右上角)开始:

path.addArcWithCenter(CGPoint(x: 300-10, y: 50), radius: 10 , startAngle: 0 , endAngle: CGFloat(M_PI/2)  , clockwise: true) //1st rounded corner

通过这样做,我有四个圆角,我只需要在代码末尾添加一条直线:

path.closePath()  

以下是代码和屏幕截图:

let path = UIBezierPath()
path.addArcWithCenter(CGPoint(x: 300-10, y: 50), radius: 10 , startAngle: 0 , endAngle: CGFloat(M_PI/2)  , clockwise: true) //1st rounded corner
path.addArcWithCenter(CGPoint(x: 200, y: 50), radius:10, startAngle: CGFloat(2 * M_PI / 3), endAngle:CGFloat(M_PI) , clockwise: true)// 2rd rounded corner
path.addArcWithCenter(CGPoint(x: 200, y: 10), radius:10, startAngle: CGFloat(M_PI), endAngle:CGFloat(3 * M_PI / 2), clockwise: true)// 3rd rounded corner
// little triangle
path.addLineToPoint(CGPoint(x:240 , y:0))
path.addLineToPoint(CGPoint(x: 245, y: -10))
path.addLineToPoint(CGPoint(x:250, y: 0))
path.addArcWithCenter(CGPoint(x: 290, y: 10), radius: 10, startAngle: CGFloat(3 * M_PI / 2), endAngle: CGFloat(2 * M_PI ), clockwise: true)
path.addLineToPoint(CGPoint(x:300 , y:50))
path.closePath()

enter image description here

答案 1 :(得分:1)

我决定选择UIBezierPath作为 Assam Al-Zookery 建议。这是Objective-C中的完整代码(应该可重用且足够灵活):

@implementation TestView

- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        self.clipsToBounds = YES;
        self.opaque = NO;
    }
    return self;
}

- (void)drawRect:(CGRect)rect {
    UIBezierPath *path = [UIBezierPath bezierPath];
    path.lineWidth = 2.0f;
    path.lineJoinStyle = kCGLineJoinRound;

    [[UIColor blackColor] setStroke];
    [[UIColor redColor] setFill];

    CGFloat arcRadius = 5.0f;
    CGFloat padding = 5.0f;
    CGFloat triangleSide = 20.0f;
    CGFloat triangleHeight = ((triangleSide * sqrtf(3.0f)) / 2);
    CGFloat rectHeight = CGRectGetHeight(rect) - triangleHeight - padding - (arcRadius * 2);

    // Top left corner
    [path addArcWithCenter:CGPointMake(arcRadius + padding, arcRadius + padding)
                    radius:arcRadius
                startAngle:DEGREES_TO_RADIANS(180)
                  endAngle:DEGREES_TO_RADIANS(270)
                 clockwise:YES];

    // Top edge
    [path addLineToPoint:CGPointMake(CGRectGetWidth(rect) - arcRadius - padding, path.currentPoint.y)];

    // Top right corner
    [path addArcWithCenter:CGPointMake(path.currentPoint.x, path.currentPoint.y + arcRadius)
                    radius:arcRadius
                startAngle:DEGREES_TO_RADIANS(270)
                  endAngle:DEGREES_TO_RADIANS(0)
                 clockwise:YES];

    // Right edge
    [path addLineToPoint:CGPointMake(CGRectGetWidth(rect) - padding, rectHeight + padding)];

    // Bottom right corner
    [path addArcWithCenter:CGPointMake(path.currentPoint.x - arcRadius, path.currentPoint.y)
                    radius:arcRadius
                startAngle:DEGREES_TO_RADIANS(0)
                  endAngle:DEGREES_TO_RADIANS(90)
                 clockwise:YES];

    // Bottom edge (right part)
    [path addLineToPoint:CGPointMake((CGRectGetWidth(rect) / 2) + (triangleSide / 2), path.currentPoint.y)];

    // Triangle
    [path addLineToPoint:CGPointMake(path.currentPoint.x - (triangleSide / 2), path.currentPoint.y + triangleHeight)];
    [path addLineToPoint:CGPointMake(path.currentPoint.x - (triangleSide / 2), path.currentPoint.y - triangleHeight)];

    // Bottom edge (left part)
    [path addLineToPoint:CGPointMake(padding + arcRadius, path.currentPoint.y)];

    // Bottom left corner
    [path addArcWithCenter:CGPointMake(path.currentPoint.x, path.currentPoint.y - arcRadius)
                    radius:arcRadius
                startAngle:DEGREES_TO_RADIANS(90)
                  endAngle:DEGREES_TO_RADIANS(180)
                 clockwise:YES];

    [path closePath];
    [path stroke];
    [path fill];
}

@end

enter image description here