178 lines
5.9 KiB
Objective-C
178 lines
5.9 KiB
Objective-C
//
|
||
// ACustomAnnotationView.m
|
||
// AMapNavIOSSDK
|
||
//
|
||
// Created by admin on 2026/3/17.
|
||
//
|
||
|
||
#import "ACustomAnnotationView.h"
|
||
|
||
// ─── 布局常量 ─────────────────────────────────────────────────────────────────
|
||
static const CGFloat kIconSize = 30; // 图标宽高
|
||
static const CGFloat kIconTextGap = 6.0; // 图标与文字间距
|
||
static const CGFloat kMaxTextWidth = 100.0; // 文字区域最大宽度
|
||
static const CGFloat kMaxTextLines = 2; // 最多行数
|
||
static const CGFloat kVPad = 4.0; // 整体上下内边距(用于 centerOffset 微调)
|
||
|
||
@interface ACustomAnnotationView ()
|
||
|
||
@property (nonatomic, strong) UIImageView *iconView;
|
||
@property (nonatomic, strong) UILabel *titleLabel;
|
||
|
||
/// 当前是否选中(用于更新图标 & 文字样式)
|
||
@property (nonatomic, assign) BOOL isAnnotationSelected;
|
||
|
||
@end
|
||
|
||
@implementation ACustomAnnotationView
|
||
|
||
#pragma mark - Init / Reuse
|
||
|
||
- (instancetype)initWithAnnotation:(id<MAAnnotation>)annotation
|
||
reuseIdentifier:(NSString *)reuseIdentifier {
|
||
self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
|
||
if (self) {
|
||
self.backgroundColor = [UIColor clearColor];
|
||
// 关闭 MAAnnotationView 自带的 image 渲染,避免干扰
|
||
self.image = nil;
|
||
[self _buildSubviews];
|
||
[self _updateFromAnnotation];
|
||
[self setNeedsLayout];
|
||
}
|
||
return self;
|
||
}
|
||
|
||
- (void)setAnnotation:(id<MAAnnotation>)annotation {
|
||
[super setAnnotation:annotation];
|
||
[self _updateFromAnnotation];
|
||
[self setNeedsLayout];
|
||
}
|
||
|
||
#pragma mark - Build
|
||
|
||
- (void)_buildSubviews {
|
||
// ── 图标 ──────────────────────────────────────────────────
|
||
if (!self.iconView) {
|
||
UIImageView *iv = [[UIImageView alloc] init];
|
||
iv.contentMode = UIViewContentModeScaleAspectFit;
|
||
[self addSubview:iv];
|
||
self.iconView = iv;
|
||
}
|
||
|
||
// ── 文字 ──────────────────────────────────────────────────
|
||
if (!self.titleLabel) {
|
||
UILabel *lbl = [[UILabel alloc] init];
|
||
lbl.numberOfLines = kMaxTextLines;
|
||
lbl.lineBreakMode = NSLineBreakByTruncatingTail;
|
||
lbl.textAlignment = NSTextAlignmentLeft;
|
||
[self addSubview:lbl];
|
||
self.titleLabel = lbl;
|
||
}
|
||
|
||
// 初始化为默认(未选中)样式
|
||
[self _applyStyle:NO];
|
||
}
|
||
|
||
/// 根据选中状态切换图标 & 文字样式
|
||
- (void)_applyStyle:(BOOL)selected {
|
||
if (selected) {
|
||
self.iconView.image = [AMapNavCommonUtil imageWithName3x:@"station_select_icon"];
|
||
self.titleLabel.font = [UIFont boldSystemFontOfSize:14];
|
||
self.titleLabel.textColor = [UIColor colorWithWhite:0.12 alpha:1.0];
|
||
} else {
|
||
self.iconView.image = [AMapNavCommonUtil imageWithName3x:@"station_normal_icon"];
|
||
self.titleLabel.font = [UIFont systemFontOfSize:13];
|
||
self.titleLabel.textColor = [UIColor colorWithWhite:0.25 alpha:1.0];
|
||
}
|
||
}
|
||
|
||
#pragma mark - Data
|
||
|
||
- (void)_updateFromAnnotation {
|
||
NSString *text = nil;
|
||
id<MAAnnotation> ann = self.annotation;
|
||
if ([ann respondsToSelector:@selector(title)]) {
|
||
text = ann.title;
|
||
}
|
||
if (text.length == 0) {
|
||
text = @"加氢站";
|
||
}
|
||
self.titleLabel.text = text;
|
||
}
|
||
|
||
#pragma mark - Selection(MAAnnotationView 官方选中回调)
|
||
|
||
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
|
||
[super setSelected:selected animated:animated];
|
||
self.isAnnotationSelected = selected;
|
||
[self _applyStyle:selected];
|
||
[self setNeedsLayout];
|
||
}
|
||
|
||
#pragma mark - Layout
|
||
|
||
- (void)layoutSubviews {
|
||
[super layoutSubviews];
|
||
|
||
// 文字最大 100pt、最多 2 行
|
||
CGSize textConstraint = CGSizeMake(kMaxTextWidth,
|
||
CGFLOAT_MAX);
|
||
CGSize textFit = [self.titleLabel sizeThatFits:textConstraint];
|
||
// 高度上限:2 行
|
||
CGFloat lineH = self.titleLabel.font.lineHeight;
|
||
CGFloat maxTextH = lineH * kMaxTextLines
|
||
+ self.titleLabel.font.leading * (kMaxTextLines - 1);
|
||
CGFloat textW = MIN(textFit.width, kMaxTextWidth);
|
||
CGFloat textH = MIN(textFit.height, maxTextH);
|
||
|
||
CGFloat totalW = kIconSize + kIconTextGap + textW;
|
||
CGFloat totalH = MAX(kIconSize, textH) + kVPad * 2;
|
||
|
||
// 更新自身 bounds
|
||
self.bounds = CGRectMake(0, 0, totalW, totalH);
|
||
|
||
// 图标:垂直居中
|
||
CGFloat iconY = (totalH - kIconSize) * 0.5;
|
||
self.iconView.frame = CGRectMake(0, iconY, kIconSize, kIconSize);
|
||
|
||
// 文字:垂直居中
|
||
CGFloat textY = (totalH - textH) * 0.5;
|
||
self.titleLabel.frame = CGRectMake(kIconSize + 1, textY, textW, textH);
|
||
|
||
// 锚点:让图标底部对齐地图坐标点
|
||
// MAAnnotationView 的 centerOffset 以 (0,0)=中心 为原点
|
||
// 默认选中图标底部对准坐标:向上偏移 totalH/2
|
||
self.centerOffset = CGPointMake(totalW / 2.0 - kIconSize / 2.0,
|
||
-(totalH / 2.0));
|
||
}
|
||
|
||
#pragma mark - Hit Test
|
||
|
||
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
|
||
UIView *hit = [super hitTest:point withEvent:event];
|
||
if (hit == self || [hit isDescendantOfView:self]) {
|
||
return self;
|
||
}
|
||
return hit;
|
||
}
|
||
|
||
#pragma mark - Touch
|
||
|
||
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
|
||
[super touchesBegan:touches withEvent:event];
|
||
|
||
id<MAAnnotation> annotation = self.annotation;
|
||
if (!annotation) return;
|
||
|
||
UIView *sv = self.superview;
|
||
while (sv && ![sv isKindOfClass:[MAMapView class]]) {
|
||
sv = sv.superview;
|
||
}
|
||
MAMapView *mapView = (MAMapView *)sv;
|
||
if (!mapView) return;
|
||
|
||
// [mapView deselectAnnotation:annotation animated:NO];
|
||
}
|
||
|
||
@end
|