iOS~ 高德地图:3、自定义气泡标注
2022-08-30 本文已影响0人
阳光下的叶子呵
(1)
添加自定义气泡
:官方文档绘制点标记
新建类CustomAnnotationView,继承MAAnnotationView或MAPinAnnotationView。若继承MAAnnotationView,则需要设置标注图标;若继承MAPinAnnotationView,使用默认的大头针标注:
WechatIMG88.jpeg(1) 新建自定义气泡类 CustomCalloutView,继承 UIView。
(2) 在 CustomCalloutView.h 中定义数据属性,包含:图片、商户名和商户地址。
GWRaderMap_LocationCustomCalloutView.h:
@interface GWRaderMap_LocationCustomCalloutView : UIView
/// 在 自定义CustomCalloutView.h 中定义数据属性,包含:背景、地址、天气图片、天气描述或温度、时间、取消按钮。
@property (nonatomic, copy) NSString *title; // 地址
@property (nonatomic, strong) UIImage *image; // 天气图片
@property (nonatomic, copy) NSString *imageUrl; // 天气图片url
@property (nonatomic, copy) NSString *detailContent; // 气温时:显示 温度,降水时:显示 天气描述
@property (nonatomic, copy) NSString *time; // 时间
@property (nonatomic, assign) NSInteger weatherCode; // 天气code
@property (nonatomic, assign) BOOL is_ShowButton;// YES 显示,NO 隐藏
@end
GWRaderMap_LocationCustomCalloutView.m:
//
// 新建自定义气泡类 CustomCalloutView,继承 UIView。
#import "GWRaderMap_LocationCustomCalloutView.h"
#define kArrorHeight 10
@interface GWRaderMap_LocationCustomCalloutView ()
/// 在 自定义CustomCalloutView.h 中定义数据属性,包含:背景、地址、天气图片、天气描述或温度、时间、取消按钮。
@property (nonatomic, strong) UIImageView *backImg; // 自定义气泡的背景图(包含背景的三角区域,半透明、有阴影)
@property (nonatomic, strong) UILabel *cityLabel;
@property (nonatomic, strong) UIImageView *weatherImgView;
@property (nonatomic, strong) UILabel *subTitleLabel;
@property (nonatomic, strong) UILabel *timeLabel;
@property (nonatomic, strong) UIButton *cancelBut; // 隐藏
@end
@implementation GWRaderMap_LocationCustomCalloutView
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = UIColor.clearColor;
[self setupUI];
}
return self;
}
- (void)setTitle:(NSString *)title {
self.cityLabel.text = title;
}
- (void)setDetailContent:(NSString *)detailContent {
self.subTitleLabel.text = detailContent;
}
- (void)setImage:(UIImage *)image {
if (image != nil) {
self.weatherImgView.image = image;
}
}
-(void)setImageUrl:(NSString *)imageUrl {
// [self.weatherImgView sd_setImageWithURL:[NSURL URLWithString:imageUrl] placeholderImage:[UIImage imageNamed:@""]];
}
- (void)setTime:(NSString *)time {
self.timeLabel.text = time;
}
- (void)setIs_ShowButton:(BOOL)is_ShowButton {
if (!is_ShowButton) {
[self removeFromSuperview];
}
}
- (void)setWeatherCode:(NSInteger)weatherCode {
self.weatherImgView.image = [UIImage imageNamed:@"raderWeather_day_sun"];
}
- (void)setupUI {
/// 左右空10 上下空20,白色卡片 118 71 整个加投影是129 111
_backImg = [[UIImageView alloc] init];
self.backImg.image = [UIImage imageNamed:@"raderMap_typhoon_bg_icon"];
[self addSubview:self.backImg];
[self.backImg makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self);
}];
_cityLabel = [[UILabel alloc] init];
_cityLabel.textColor = RGBA(153, 153, 153, 1);
_cityLabel.textAlignment = NSTextAlignmentLeft;
_cityLabel.font = FontSourceHanSerifCN_Heavy([UIScreen mainScreen].bounds.size.width/375*10);
// _cityLabel.font = [UIFont systemFontOfSize:[UIScreen mainScreen].bounds.size.width/375*10 weight:UIFontWeightRegular];
_cityLabel.adjustsFontSizeToFitWidth = YES;
_cityLabel.minimumScaleFactor = 0.2;
[self addSubview:self.cityLabel];
[self.cityLabel makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(self.mas_top).offset([UIScreen mainScreen].bounds.size.width/375*8);
make.left.mas_equalTo(self.mas_left).offset([UIScreen mainScreen].bounds.size.width/375*8);
make.right.mas_equalTo(self.mas_right).offset(-[UIScreen mainScreen].bounds.size.width/375*25);
}];
_weatherImgView = [[UIImageView alloc] init];
[self addSubview:self.weatherImgView];
[self.weatherImgView makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(self.self.cityLabel.mas_bottom).offset([UIScreen mainScreen].bounds.size.width/375*1);
make.left.mas_equalTo(self.mas_left).offset([UIScreen mainScreen].bounds.size.width/375*8);
make.width.mas_equalTo([UIScreen mainScreen].bounds.size.width/375*28);
make.height.mas_equalTo([UIScreen mainScreen].bounds.size.width/375*22);
}];
_subTitleLabel = [[UILabel alloc] init];
_subTitleLabel.textColor = RGBA(102, 102, 102, 1);
_subTitleLabel.textAlignment = NSTextAlignmentLeft;
_subTitleLabel.font = FontSourceHanSerifCN_Heavy([UIScreen mainScreen].bounds.size.width/375*12);
_subTitleLabel.adjustsFontSizeToFitWidth = YES;
_subTitleLabel.minimumScaleFactor = 0.2;
[self addSubview:self.subTitleLabel];
[self.subTitleLabel makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(self.weatherImgView.mas_bottom).offset([UIScreen mainScreen].bounds.size.width/375*1);
make.left.mas_equalTo(self.mas_left).offset([UIScreen mainScreen].bounds.size.width/375*8);
make.right.mas_equalTo(self.mas_right).offset(-[UIScreen mainScreen].bounds.size.width/375*35);
}];
_timeLabel = [[UILabel alloc] init];
_timeLabel.textColor = RGBA(102, 102, 102, 1);
_timeLabel.textAlignment = NSTextAlignmentRight;
_timeLabel.font = FontSourceHanSerifCN_Heavy([UIScreen mainScreen].bounds.size.width/375*12);
[self addSubview:self.timeLabel];
[self.timeLabel makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(self.subTitleLabel);
make.right.mas_equalTo(self.mas_right).offset(-[UIScreen mainScreen].bounds.size.width/375*8);
}];
// 实现气泡点击需要设置右侧的点击详情按钮,但是需要将创建的button类型设置为除默认类型如UIButtonTypeSystem
_cancelBut = [UIButton buttonWithType:UIButtonTypeCustom];
[_cancelBut setBackgroundImage:[UIImage imageNamed:@"raderMap_CancelWeatherView_icon"] forState:UIControlStateNormal];
_cancelBut.adjustsImageWhenHighlighted = NO; // 下面的背景图片可以保证图片不变灰
[self addSubview:self.cancelBut];
[self.cancelBut makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(self.cityLabel);
make.right.mas_equalTo(self.mas_right).offset(-[UIScreen mainScreen].bounds.size.width/375*8);
make.height.width.mas_equalTo([UIScreen mainScreen].bounds.size.width/375*16);
}];
[self.cancelBut addTarget:self action:@selector(clickCancelAction) forControlEvents:UIControlEventTouchUpInside];
/**
self.cityLabel.backgroundColor = UIColor.whiteColor;
self.weatherImgView.backgroundColor = UIColor.whiteColor;
self.subTitleLabel.backgroundColor = UIColor.whiteColor;
self.timeLabel.backgroundColor = UIColor.whiteColor;
self.cancelBut.backgroundColor = UIColor.whiteColor;
*/
}
- (void)clickCancelAction {
// [LCM_AlertViewFactory showToastWithMessage:@"点击 隐藏按钮"];
}
/**
#pragma mark -- 绘制背景 (不推荐这种,会有视觉问题) --
- (void)drawRect:(CGRect)rect {
[self drawInContext:UIGraphicsGetCurrentContext()];
self.layer.shadowColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.4].CGColor;
self.layer.shadowOpacity = 1.0;
self.layer.shadowOffset = CGSizeMake(0.0f, 0.0f);
}
- (void)drawInContext:(CGContextRef)context {
CGContextSetLineWidth(context, 1.0);
CGContextSetFillColorWithColor(context, [UIColor colorWithRed:255 green:255 blue:255 alpha:1].CGColor);
[self getDrawPath:context];
CGContextFillPath(context);
}
- (void)getDrawPath:(CGContextRef)context {
CGRect rrect = self.bounds;
CGFloat radius = [UIScreen mainScreen].bounds.size.width/375*8;
CGFloat minx = CGRectGetMinX(rrect),
midx = CGRectGetMidX(rrect),
maxx = CGRectGetMaxX(rrect);
CGFloat miny = CGRectGetMinY(rrect),
maxy = CGRectGetMaxY(rrect)-kArrorHeight;
CGContextMoveToPoint(context, midx+kArrorHeight, maxy);
CGContextAddLineToPoint(context,midx, maxy+kArrorHeight);
CGContextAddLineToPoint(context,midx-kArrorHeight, maxy);
CGContextAddArcToPoint(context, minx, maxy, minx, miny, radius);
CGContextAddArcToPoint(context, minx, minx, maxx, miny, radius);
CGContextAddArcToPoint(context, maxx, miny, maxx, maxx, radius);
CGContextAddArcToPoint(context, maxx, maxy, midx, maxy, radius);
CGContextClosePath(context);
}
*/
@end
GWRaderMap_CustomAnnotationView.h:
///(1) 新建类CustomAnnotationView,继承MAAnnotationView或MAPinAnnotationView。若继承MAAnnotationView,则需要设置标注图标;若继承MAPinAnnotationView,使用默认的大头针标注
#import <MAMapKit/MAMapKit.h>
#import "GWRaderMap_LocationCustomCalloutView.h" // 新建自定义气泡类 CustomCalloutView,继承 UIView
NS_ASSUME_NONNULL_BEGIN
@interface GWRaderMap_CustomAnnotationView : MAAnnotationView
///(2) 在CustomAnnotationView.h中定义自定义气泡属性
@property (nonatomic, readonly) GWRaderMap_LocationCustomCalloutView *calloutView;
/// 【赋值】:在 自定义CustomCalloutView.h 中定义数据属性,包含:背景、地址、天气图片、天气描述或温度、时间、取消按钮。
@property (nonatomic, copy) NSString *title; // 地址
@property (nonatomic, copy) NSString *imageUrl; // 天气图片url
@property (nonatomic, copy) NSString *detailContent; // 气温时:显示 温度,降水时:显示 天气描述
@property (nonatomic, copy) NSString *time; // 时间
@property (nonatomic, assign) NSInteger weatherCode; // 天气code
@property (nonatomic, assign) BOOL is_ShowButton;// YES 显示,NO 隐藏
/// 点击自定义按钮,隐藏整个“气泡” 和 “大头针”:
@property (nonatomic, copy) void (^hideCustomCalloutViewBlock) (BOOL is_hideCustomView);
@end
NS_ASSUME_NONNULL_END
GWRaderMap_CustomAnnotationView.m:
//
// Created by Geraint on 2022/8/26.
//
#import "GWRaderMap_CustomAnnotationView.h"
@interface GWRaderMap_CustomAnnotationView ()
/// (3) 在CustomAnnotationView.m中修改calloutView属性
@property (nonatomic, strong, readwrite) GWRaderMap_LocationCustomCalloutView *calloutView;
@property (nonatomic, strong) UIButton *cancelBut; // 隐藏
@end
@implementation GWRaderMap_CustomAnnotationView
- (instancetype)initWithAnnotation:(id<MAAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
if (self) {
}
return self;
}
- (void)prepareForReuse {
[super prepareForReuse];
}
- (void)clickCancelAction {
// [LCM_AlertViewFactory showToastWithMessage:@"👌👌👌👌点击 隐藏按钮"];
// [self setSelected:NO animated:YES]; // 这样设置,大头针未消失,所以改用block
// 或者在外部这样设置(即,下边的block回调中设置)
// 只隐藏自定义气泡,大头针不隐藏:
// [self.mapView deselectAnnotation:self.locatinWeather_AnimatedAnnotation animated:YES];
if (self.hideCustomCalloutViewBlock) {
self.hideCustomCalloutViewBlock(YES);
}
}
///(4) 重写选中方法setSelected。选中时新建并添加calloutView,传入数据;非选中时删除calloutView。
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
///设置是否处于选中状态, 外部如果要选中请使用mapView的selectAnnotation方法
if (self.selected == selected) {
return;
}
if (selected)
{
if (self.calloutView == nil) {
// 创建
self.calloutView = [[GWRaderMap_LocationCustomCalloutView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width/375*118, [UIScreen mainScreen].bounds.size.width/375*81)];
self.calloutView.center = CGPointMake(CGRectGetWidth(self.bounds) / 2.f + self.calloutOffset.x,
-CGRectGetHeight(self.calloutView.bounds) / 2.f + self.calloutOffset.y);
}
// self.calloutView.image = [UIImage imageNamed:@"building"]; // 注意:提前导入building.png图片。
// self.calloutView.title = self.annotation.title;
// self.calloutView.subtitle = self.annotation.subtitle;
self.imageView.backgroundColor = UIColor.clearColor;
self.image = [UIImage imageNamed:@"raderMap_Location_icon"]; // 大头钉图片
/// 在 自定义CustomCalloutView.h 中定义数据属性,包含:背景、地址、天气图片、天气描述或温度、时间、取消按钮。
self.calloutView.title = self.title;
self.calloutView.imageUrl = self.imageUrl;
//self.calloutView.image = [UIImage imageNamed:@""]; // 直接传值图片
self.calloutView.detailContent = self.detailContent;
self.calloutView.time = self.time;
self.calloutView.is_ShowButton = self.is_ShowButton;
self.calloutView.weatherCode = self.weatherCode;
[self addSubview:self.calloutView];
self.calloutView.backgroundColor = UIColor.clearColor;
[self setupUI];
}
else
{
[self.calloutView removeFromSuperview];
}
[super setSelected:selected animated:animated];
}
- (void)setupUI {
// 因为自定义的气泡是添加到大头针上的,而大头针的size只有下面很小一部分(self.imageView范围),所以calloutView是在大头针的外面的。 而 iOS 按钮超过父视图范围是无法响应事件的处理方法。所以就要重写hittest方法。
_cancelBut = [UIButton buttonWithType:UIButtonTypeCustom];
self.cancelBut.backgroundColor = UIColor.clearColor;
[self.calloutView addSubview:self.cancelBut];
[self.cancelBut makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.calloutView);
}];
[self.cancelBut addTarget:self action:@selector(clickCancelAction) forControlEvents:UIControlEventTouchUpInside];
}
#pragma mark -- 在CustomAnnotationView.m 中 重写 hittest 方法
/// 自定义 UIButton,添加到这个CustomAnnotationView上,点击事件
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
UIView *view = [super hitTest:point withEvent:event];
if (view == nil) {
CGPoint tempoint = [self.cancelBut convertPoint:point fromView:self];
if (CGRectContainsPoint(self.cancelBut.bounds, tempoint)) {
view = self.cancelBut;
}
}
return view;
}
//// 在CustomAnnotationView.m中重写hittest方法:(这里的self.calloutView.navBtn 就是你需要点击的按钮)
//- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
// UIView *view = [super hitTest:point withEvent:event];
// if (view == nil) {
// CGPoint tempoint = [self.calloutView.navBtn convertPoint:point fromView:self];
// if (CGRectContainsPoint(self.calloutView.navBtn.bounds, tempoint)) {
// view = self.calloutView.navBtn;
// }
// }
// return view;
//}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
}
*/
@end