好文

iOS~ 高德地图:3、自定义气泡标注

2022-08-30  本文已影响0人  阳光下的叶子呵

新建类CustomAnnotationView,继承MAAnnotationView或MAPinAnnotationView。若继承MAAnnotationView,则需要设置标注图标;若继承MAPinAnnotationView,使用默认的大头针标注:

(1) 新建自定义气泡类 CustomCalloutView,继承 UIView。
(2) 在 CustomCalloutView.h 中定义数据属性,包含:图片、商户名和商户地址。

WechatIMG88.jpeg

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

上一篇 下一篇

猜你喜欢

热点阅读