【问题标题】:iOS Custom Annotation: A view below the annotation piniOS 自定义注解:注解图钉下方的视图
【发布时间】:2015-05-22 12:28:16
【问题描述】:

我需要用我的自定义注释视图替换默认注释视图。

我需要做以下事情:

  1. 自定义注释视图,其中嵌入了图像视图。
  2. 它下面的一个视图,其中包含一个标签。

更多说明请看图片:

在上图中,我需要在空白区域放置一个图像视图,您可以在图像中以圆形形式看到它,接下来我还需要添加一个包含标签的视图,我可以在该标签上设置像我一样的任何文本、朋友等等…​​…

因此,为此,我搜索了许多有关堆栈溢出的问题,但没有得到答案。我不希望它被调用,我只想在渲染地图时将它作为注释。我试图为此创建一个自定义类,但不知道如何处理。

我们将不胜感激任何帮助

【问题讨论】:

  • 获取图像并使用以下网址在其上添加文本stackoverflow.com/questions/6992830/…,然后使用该输出图像作为注释引脚。
  • 该问题如何与自定义注释相关联?
  • 你想用文字创建图像吗?
  • 看看我上传的图片我需要创建一个自定义注释,里面有一个自定义图像,下面有一个包含标签的自定义视图
  • 你说的是图钉或标注视图?

标签: ios objective-c mapkit mapkitannotation


【解决方案1】:

您可以创建自己的注释视图:

@import MapKit;

@interface CustomAnnotationView : MKAnnotationView

@end

@interface CustomAnnotationView ()
@property (nonatomic) CGSize textSize;
@property (nonatomic) CGSize textBubbleSize;
@property (nonatomic, weak) UILabel *label;
@property (nonatomic) CGFloat lineWidth;
@property (nonatomic) CGFloat pinRadius;
@property (nonatomic) CGFloat pinHeight;

@property (nonatomic, strong) UIBezierPath *pinPath;
@property (nonatomic, strong) UIBezierPath *textBubblePath;
@end

@implementation CustomAnnotationView

- (instancetype)initWithAnnotation:(id<MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
    if (self) {
        self.lineWidth = 1.0;
        self.pinHeight = 40;
        self.pinRadius = 15;

        UILabel *label = [[UILabel alloc] init];
        label.textAlignment = NSTextAlignmentCenter;
        label.font = [UIFont preferredFontForTextStyle:UIFontTextStyleCallout];
        label.textColor = [UIColor whiteColor];
        [self addSubview:label];
        self.label = label;

        [self adjustLabelWidth:annotation];

        self.opaque = false;
    }
    return self;
}

- (void)setAnnotation:(id<MKAnnotation>)annotation {
    [super setAnnotation:annotation];
    if (annotation) [self adjustLabelWidth:annotation];
}

- (void)adjustLabelWidth:(id<MKAnnotation>)annotation {
    NSString *title = [annotation title];
    NSDictionary *attributes = @{NSFontAttributeName : self.label.font};
    self.textSize = [title sizeWithAttributes:attributes];
    CGFloat delta = self.textSize.height * (1.0 - sinf(M_PI_4)) * 0.55;
    self.textBubbleSize = CGSizeMake(self.textSize.width + delta * 2, self.textSize.height + delta * 2);
    self.label.frame = CGRectMake(0, self.pinHeight, self.textBubbleSize.width, self.textBubbleSize.height);
    self.label.text = title;
    self.frame = CGRectMake(0, 0, self.textBubbleSize.width, self.pinHeight + self.textBubbleSize.height);
    self.centerOffset = CGPointMake(0, self.frame.size.height / 2.0 - self.pinHeight);
}

- (void)drawRect:(CGRect)rect {
    CGFloat radius = self.pinRadius - self.lineWidth / 2.0;
    CGPoint startPoint = CGPointMake(self.textBubbleSize.width / 2.0, self.pinHeight);
    CGPoint center = CGPointMake(self.textBubbleSize.width / 2, self.pinRadius);
    CGPoint nextPoint;

    // pin

    self.pinPath = [UIBezierPath bezierPath];
    [self.pinPath moveToPoint:startPoint];
    nextPoint = CGPointMake(self.textBubbleSize.width / 2 - radius, self.pinRadius);
    [self.pinPath addCurveToPoint:nextPoint
                    controlPoint1:CGPointMake(startPoint.x, startPoint.y - (startPoint.y - nextPoint.y) / 2.0)
                    controlPoint2:CGPointMake(nextPoint.x, nextPoint.y + (startPoint.y - nextPoint.y) / 2.0)];

    [self.pinPath addArcWithCenter:center radius:radius startAngle:M_PI endAngle:0 clockwise:TRUE];
    nextPoint = startPoint;
    startPoint = self.pinPath.currentPoint;
    [self.pinPath addCurveToPoint:nextPoint
                    controlPoint1:CGPointMake(startPoint.x, startPoint.y - (startPoint.y - nextPoint.y) / 2.0)
                    controlPoint2:CGPointMake(nextPoint.x, nextPoint.y + (startPoint.y - nextPoint.y) / 2.0)];
    [[UIColor blackColor] setStroke];
    [[UIColor colorWithRed:0.0 green:0.5 blue:1.0 alpha:0.8] setFill];
    self.pinPath.lineWidth = self.lineWidth;
    [self.pinPath fill];
    [self.pinPath stroke];
    [self.pinPath closePath];

    // bubble around label

    if ([self.annotation.title length] > 0) {
        self.textBubblePath = [UIBezierPath bezierPath];
        CGRect bubbleRect = CGRectInset(CGRectMake(0, self.pinHeight, self.textBubbleSize.width, self.textBubbleSize.height), self.lineWidth / 2, self.lineWidth / 2);
        self.textBubblePath = [UIBezierPath bezierPathWithRoundedRect:bubbleRect
                                                         cornerRadius:bubbleRect.size.height / 2];
        self.textBubblePath.lineWidth = self.lineWidth;
        [self.textBubblePath fill];
        [self.textBubblePath stroke];
    } else {
        self.textBubblePath = nil;
    }

    // center white dot

    self.pinPath = [UIBezierPath bezierPathWithArcCenter:center radius:radius / 3.0 startAngle:0 endAngle:M_PI * 2.0 clockwise:TRUE];
    self.pinPath.lineWidth = self.lineWidth;
    [[UIColor whiteColor] setFill];
    [self.pinPath fill];
}

- (UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event {
    if ([self.pinPath containsPoint:point] || [self.textBubblePath containsPoint:point])
        return self;

    return nil;
}

@end

这会产生如下内容:

显然,您可以随心所欲地对其进行自定义,但它说明了基本思想:编写一个覆盖initWithAnnotation:reuseIdentifier:MKAnnotationView 子类并实现您自己的drawRect

【讨论】:

  • 我们不能在 viewforannotation 委托方法中只返回一个自定义视图吗?其中自定义视图将包含两个图像视图
  • 是的,您还可以创建自定义图像并将其用于注释视图的图像。事实上,如果不同注解的注解视图相同,那就更可取了。但在我的示例中,每个都是不同的,因此自定义 drawRect 是有意义的。顺便说一句,即使您使用自定义图像,而不是drawRect,您也可以在MKAnnotationView 子类(代替自定义drawRect)或viewForAnnotation 中执行此操作。恕我直言,这种复杂的渲染不适合在 viewForAnnotation 内部,甚至在地图视图委托中。
  • @RajatDeepSingh 加入我的聊天chat.stackoverflow.com/rooms/79037/…
  • 对于在 iOS 11 下绘制自定义注释时遇到问题的人,请务必为注释视图设置大小,就像在这个出色的示例中一样。
猜你喜欢
  • 2023-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-28
相关资源
最近更新 更多