ios 百度地图自定义地图弹出框(CalloutView)
来源:互联网 发布:科比职业生涯总数据 编辑:程序博客网 时间:2024/05/16 12:48
前言
自己之前没怎么用过地图,这两天自己来使用地图,研究了下大头针的弹出框,一开始觉得很蛋疼,后来看看别人的代码和博客,也差不多,主要大家要理解原理!
在ios上边使用地图库的同学肯定遇到过这样的问题:弹出框只能设置title和subtitle和左右的view,不管是百度地图还是高德地图还是自带的google地图,只提供了这四个属性,如果想添加更多的view,只能自定义。可是,类库只能看到.h文件,.m都看不到,这让新手比较蛋疼,庞大的地图类库一时半会摸不着头脑,从头再学还需要时间,本文就教大家快速制作一个属于自己的 CalloutView!等你一步一步调通后,再回过头来使用系统自带的方法设置callout,就会领悟这个过程。这里也很多是从别人那里学来的,大家相互学习,资源共享,分享技术!
Step1
创建demo,并添加百度地图的静态类库,helloword能显示mapview
关于这一步我专门写了教程,这里就不再赘述,同样,关于如何使用自带的BMKPointAnnotation添加一个marker,我也不再说了,如果连这个你都不会,那么先去官网看一下基本教程。
Step2
实现三个委托方法:
这个方法类似tableview添加cell,都是创建annotation
#pragma mark --#pragma mark --根据anntation生成对应的View// 根据anntation生成对应的View- (BMKAnnotationView *)mapView:(BMKMapView *)mapView viewForAnnotation:(id <BMKAnnotation>)annotation这个方法在点击地图marker时所触发(并显示callout)
#pragma mark--当点击annotation views时,调用此接口//点击大头针-(void)mapView:(BMKMapView *)mapView didSelectAnnotationView:(BMKAnnotationView *)view{这个方法在点击地图任意位置,相当于隐藏callout
#pragma mark--取消选中一个annotation views时,调用此接口- (void)mapView:(BMKMapView *)mapView didDeselectAnnotationView:(BMKAnnotationView *)view{
原理:地图上的marker是在viewForAnnoation里创建的,同时也会隐含的为我们创建一个CalloutView,就是自带的吹出框,只是我们看不到源码。其实这个吹出框(CalloutView)也是一个annotation,也会在viewForAnnotation里被创建,他的坐标应该和这个点的marker坐标一样,只要明白了这一点,就行了,marker和吹出框是两个不同的annotation,他们有同样的coordinate。
Step3
自定义一个Annotation,为了简单方便,我就直接继承了mapview自带的BMKPointAnnotation,这是一个经典的图钉marker。
在这里我添加了一个Dictionary属性,目的是为了自定义的CalloutView弹出框显示内容赋值,一会就明白了。
Step4
添加自定义Annotation到mapview
//添加自定义Annotation CLLocationCoordinate2D center = {39.91669,116.39716}; CustomPointAnnotation *pointAnnotation = [[CustomPointAnnotation alloc] init]; pointAnnotation.title = @"我是中国人";//因为继承了BMKPointAnnotation,所以这些title,subtitle都可以设置 pointAnnotation.subtitle = @"我爱自己的祖国"; pointAnnotation.coordinate = center; [mymapview addAnnotation:pointAnnotation];在viewForanntion里,由于我对marker没太大要求,直接使用了BMKPinAnnotationView(图钉),简单设置image属性为自己需要的图标,如下所示:
展示一个效果图:(这个图是别人那里弄来的,自己太懒了,我自己测试了是可以的显示的)
显然CalloutView只能设置title和subtitle,无法满足我们的要求,那么继续下一步。
Step5
创建一个(自定义的CalloutView)的Annotation,相当于显示calloutView的annotation。
[注意] 继承自NSObject<BMKAnnotation>
CalloutMapAnnotation.h#import <Foundation/Foundation.h>#import "BMapKit.h"@interface CalloutMapAnnotation : NSObject<BMKAnnotation>@property (nonatomic) CLLocationDegrees latitude;@property (nonatomic) CLLocationDegrees longitude;@property(strong,nonatomic) NSDictionary *locationInfo;//callout吹出框要显示的各信息- (id)initWithLatitude:(CLLocationDegrees)lat andLongitude:(CLLocationDegrees)lon;@end
CalloutMapAnnotation.m
#import "CalloutMapAnnotation.h"@implementation CalloutMapAnnotation@synthesize latitude;@synthesize longitude;@synthesize locationInfo;- (id)initWithLatitude:(CLLocationDegrees)lat andLongitude:(CLLocationDegrees)lon { if (self = [super init]) { self.latitude = lat; self.longitude = lon; } return self;}-(CLLocationCoordinate2D)coordinate{ CLLocationCoordinate2D coordinate; coordinate.latitude = self.latitude; coordinate.longitude = self.longitude; return coordinate; }@end
这里设置了经纬度的属性,和一个init初始化经纬度的方法(经纬度=marker的经纬度),同样添加了一个Dictionary的属性,为了传递在CalloutView上内容的赋值,继续。
Step6
这一步我们创建自定义的View,想要什么布局就写什么样的布局,想要多少属性就加多少属性,
[注意:继承自BMKAnnotationView]
CallOutAnnotationView.h#import "BMKAnnotationView.h"#import "BusPointCell.h"@interface CallOutAnnotationView : BMKAnnotationView@property(nonatomic,strong) UIView *contentView;//添加一个UIView@property(nonatomic,strong) BusPointCell *busInfoView;//在创建calloutView Annotation时,把contentView add的 subview赋值给businfoView@end
BusPointCell是ContentView里的subview,这个view就是显示各个组件,并赋不同的值
CallOutAnnotationView.m
#import "CallOutAnnotationView.h"#import <QuartzCore/QuartzCore.h>#define Arror_height 6@implementation CallOutAnnotationView@synthesize contentView;@synthesize busInfoView;- (id)initWithFrame:(CGRect)frame{ self = [super initWithFrame:frame]; if (self) { // Initialization code } return self;}-(void)dealloc{ [contentView removeFromSuperview]; contentView = nil; [busInfoView removeFromSuperview]; busInfoView = nil;}-(id)initWithAnnotation:(id<BMKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier{ self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier]; if (self) { self.backgroundColor = [UIColor clearColor]; self.canShowCallout = NO; self.centerOffset = CGPointMake(0, -55); self.frame = CGRectMake(0, 0, 240, 80); self.contentView = [[UIView alloc] initWithFrame:CGRectMake(5, 5, self.frame.size.width-15, self.frame.size.height-15)]; self.contentView.backgroundColor = [UIColor clearColor]; [self addSubview:self.contentView]; } return self;}-(void)drawInContext:(CGContextRef)context{ CGContextSetLineWidth(context, 2.0); CGContextSetFillColorWithColor(context, [UIColor colorWithRed:255.0/255.0 green:255.0/255.0 blue:255.0/255.0 alpha:1.0].CGColor); [self getDrawPath:context]; CGContextFillPath(context); }- (void)getDrawPath:(CGContextRef)context{ CGRect rrect = self.bounds; CGFloat radius = 6.0; CGFloat minx = CGRectGetMinX(rrect), midx = CGRectGetMidX(rrect), maxx = CGRectGetMaxX(rrect); CGFloat miny = CGRectGetMinY(rrect), // midy = CGRectGetMidY(rrect), maxy = CGRectGetMaxY(rrect)-Arror_height; CGContextMoveToPoint(context, midx+Arror_height, maxy); CGContextAddLineToPoint(context,midx, maxy+Arror_height); CGContextAddLineToPoint(context,midx-Arror_height, 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);}/*// Only override drawRect: if you perform custom drawing.// An empty implementation adversely affects performance during animation.- (void)drawRect:(CGRect)rect{ // Drawing code}*/@end
BusPointCell.h
想要多少label,就可以有多少label
#import <UIKit/UIKit.h>@interface BusPointCell : UIView@property (strong, nonatomic) UIImageView *iconImageView;@property (strong, nonatomic) UILabel *titleLabel;@property (strong, nonatomic) UILabel *contentLabel;@property (strong, nonatomic) UILabel *decLabel;@end
BusPointCell.m
#import "BusPointCell.h"@implementation BusPointCell- (id)initWithFrame:(CGRect)frame{ self = [super initWithFrame:frame]; if (self) { // Initialization code [self loadSubViews]; } return self;}-(id)init{ self = [super init]; if (self != nil) { } return self;}-(void)loadSubViews{ _iconImageView = [[UIImageView alloc] init]; _iconImageView.backgroundColor = [UIColor redColor]; _iconImageView.frame = CGRectMake(5, 5, 40, 40); [self addSubview:_iconImageView]; _titleLabel = [[UILabel alloc] init]; _titleLabel.backgroundColor = [UIColor blackColor]; _titleLabel.font = [UIFont systemFontOfSize:15]; _titleLabel.textColor = [UIColor blackColor]; _titleLabel.numberOfLines = 0; _titleLabel.lineBreakMode = 0; _titleLabel.frame = CGRectMake(CGRectGetMaxX(_iconImageView.frame)+2, CGRectGetMidY(_iconImageView.frame), 100, 45); [self addSubview:_titleLabel];}
我上面的的这个BusPointCell类里面的东西是随便写的,没有排版,你们要根据自己的需要排版!
Step7
自定义的CalloutView都准备妥当,现在就是要实现他们的部分了,简单说一下原理,在didSelectAnnotationView函数里创建并添加calloutview的annotation(CalloutMapAnnotation),然后在viewForAnnotation函数内实例化要显示的calloutview(CallOutAnnotationView)
首先声明一个局部变量CalloutMapAnnotation *_calloutMapAnnotation;
在didSelectAnnotationView函数内添加如下代码:
-(void)mapView:(BMKMapView *)mapView didSelectAnnotationView:(BMKAnnotationView *)view{ DEBugMethod(); //CustomPointAnnotation 是自定义的marker标注点,通过这个来得到添加marker时设置的pointCalloutInfo属性 CustomPointAnnotation *annn = (CustomPointAnnotation*)view.annotation; if ([view.annotation isKindOfClass:[CustomPointAnnotation class]]) { //如果点到了这个marker点,什么也不做 if (_calloutMapAnnotation.coordinate.latitude == view.annotation.coordinate.latitude&& _calloutMapAnnotation.coordinate.longitude == view.annotation.coordinate.longitude) { return; } //如果当前显示着calloutview,又触发了select方法,删除这个calloutview annotation if (_calloutMapAnnotation) { [mapView removeAnnotation:_calloutMapAnnotation]; _calloutMapAnnotation=nil; } //创建搭载自定义calloutview的annotation _calloutMapAnnotation = [[CalloutMapAnnotation alloc] initWithLatitude:view.annotation.coordinate.latitude andLongitude:view.annotation.coordinate.longitude]; //把通过marker(ZNBCPointAnnotation)设置的pointCalloutInfo信息赋值给CalloutMapAnnotation _calloutMapAnnotation.locationInfo = annn.pointCalloutInfo; [mapView addAnnotation:_calloutMapAnnotation]; [mapView setCenterCoordinate:view.annotation.coordinate animated:YES]; }}
其次,要在viewForAnnotation里创建我们的calloutview(CallOutAnnotationView),添加如下代码:
else if ([annotation isKindOfClass:[CalloutMapAnnotation class]]){ //此时annotation就是我们calloutview的annotation CalloutMapAnnotation *ann = (CalloutMapAnnotation*)annotation; //如果可以重用 CallOutAnnotationView *calloutannotationview = (CallOutAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:@"calloutview"]; //否则创建新的calloutView if (!calloutannotationview) { calloutannotationview = [[CallOutAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"calloutview"]; BusPointCell *cell =[[BusPointCell alloc] init];// [[[NSBundle mainBundle] loadNibNamed:@"BusPointCell" owner:self options:nil] objectAtIndex:0]; cell.frame = CGRectMake(0, 0, 120, 50); [calloutannotationview.contentView addSubview:cell]; calloutannotationview.busInfoView = cell; } //开始设置添加marker时的赋值 calloutannotationview.busInfoView.titleLabel.text = [ann.locationInfo objectForKey:@"title"]; calloutannotationview.busInfoView.contentLabel.text = [ann.locationInfo objectForKey:@"content"]; calloutannotationview.busInfoView.decLabel.text =[ann.locationInfo objectForKey:@"dec"]; return calloutannotationview;
[注意]在添加marker的判断里一定要设置markerannotation.canShowCallout =NO; 否则点击marker会默认显示系统的弹出框
Step8
calloutview的annotation也创建和添加了,接下来我们就设置一下marker对应吹出框的数据:
然后运行一下:
搞定了吧,具体布局可以自己通过code方式,或xib方式设计,目前点击marker能显示了,可是点击其它区域还是无法显示,所以我们在didDeselectAnnotationView方法里还需要判断一下,remove掉。
#pragma mark--取消选中一个annotation views时,调用此接口- (void)mapView:(BMKMapView *)mapView didDeselectAnnotationView:(BMKAnnotationView *)view{ DEBugMethod(); if (_calloutMapAnnotation&&![view isKindOfClass:[CallOutAnnotationView class]]) { if (_calloutMapAnnotation.coordinate.latitude == view.annotation.coordinate.latitude&& _calloutMapAnnotation.coordinate.longitude == view.annotation.coordinate.longitude) { [mapView removeAnnotation:_calloutMapAnnotation]; _calloutMapAnnotation = nil; } }}
最后
之所以在显示marker的annotation[本文为CustomPointAnnotation]和显示calloutview的annotation[本文为CalloutMapAnnotation]里各添加一个Dictionary,就是要在点击时通过marker传递数据,添加时通过calloutview的annotation实例来设置每一个属性的数据,已达到不同的maker,显示不同的数据。
我的过程是按照自己的思维来说的,可能大家理解起来不是太清晰,自己仔细研究一下这三个函数和mapview自带的callout调用过程,应该大家差不多也可以理解了。- ios 百度地图自定义地图弹出框(CalloutView)
- ios 一步一步学会自定义地图吹出框(CalloutView)-->(百度地图,高德地图,google地图)
- ios 一步一步学会自定义地图吹出框(CalloutView)-->(百度地图,高德地图,google地图)
- ios 一步一步学会自定义地图吹出框(CalloutView)-->(百度地图,高德地图,google地图)
- ios 一步一步学会自定义地图吹出框(CalloutView)-->(百度地图,高德地图,google地图)
- ios 自定义地图吹出框(CalloutView)-->(百度地图,高德地图,google地图)
- ios 一步一步学会自定义地图吹出框(CalloutView)-->(百度地图,高德地图,google地图)
- ios 高德地图 默认弹出吹出框(calloutView)
- 百度地图弹出自定义框
- 高德地图(百度地图,Google地图)中自定义Annotation&CallOutView
- IOS 自定义地图弹出框
- IOS地图自定义弹出框
- iOS百度地图自定义
- IOS 调用百度地图(SDK) 进行定位以及自定义位置弹出框(气泡)
- iOS 百度地图自定义大头针。
- 百度地图自定义弹出气泡和大头针
- Swift 百度地图自定义弹出视图
- js 百度地图自定义弹出信息窗口
- .NET SqlHelper类
- CentOS 安装 clamav
- 页面禁用返回功能
- ibeacons 基站模拟
- openjudge 距离排序
- ios 百度地图自定义地图弹出框(CalloutView)
- erlang字符串操作
- Leetcode_unique-paths-ii
- 【jQuery】事件 小汇总
- Children’s Queue
- 不丹活佛
- maven核心,pom.xml详解
- Ubuntu安装eclipse
- nginx和tomcat的简单整合