美文网首页好文
iOS~ 高德地图:3、自定义气泡标注

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

作者: 阳光下的叶子呵 | 来源:发表于2022-08-30 15:07 被阅读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
    
    

    相关文章

      网友评论

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

        本文链接:https://www.haomeiwen.com/subject/nlilnrtx.html