地图系列之三 自定义大头针视图
自定义大头针视图控件
- 点击大头针会出现一个弹框显示一些内容,这个弹框的样式是系统自定义的,而且iOS各个系统还会有差异,因此为了统一,需要自定义这个弹框
- 思路:
- 监听大头针的点击
- 在该大头针上面在扎(添加)一颗大的大头针视图
- 这个大头针视图需要自定义(
ZHDefineAlertAnnotationView
)- 继承自
MKAnnotationView
- 根据需要设置自己的frame/以及内部添加所需控件(
ZHDefineAlertView
) - 重写
setAnnotation
拿到数据,给子控件设置数据
- 继承自
- 这个自定义大头针视图对应的大头针模型也需要自定义
- 自定义一个大头针模型,遵守
MKAnnotation
协议(ZHDefineAlertAnnotation
) - 该模型内部可以搞一个数据源属性,方便存储数据(
ZHDefineDataModel
)
- 自定义一个大头针模型,遵守
- 一旦添加这个自定义大头针模型,就会到数据源方法
viewForAnnotation
获取对应的自定义大头针视图
- 重写大头针视图数据源方法(
viewForAnnotation
)- 用户位置大头针模型
MKUserLocation
,返回nil - 判断是系统自带弹框对应的大头针模型
ZHAnnotation
- 做相应的数据配置
- 判断是自定义弹框对应的大头针模型
ZHDefineAlertAnnotation
- 自定义大头针视图控件(与系统自带的
MKAnnotationView
作对比),继承自MKAnnotationView
—ZHDefineAlertAnnotationView
- 这个(
ZHDefineAlertAnnotationView
)View是一个空白控件,需要根据自己的需要添加子控件,因此从写initWithFrame
方法,内部添加子控件 - 为了方便使用xib搭建创建了一个
ZHDefineAlertView
子View
- 自定义大头针视图控件(与系统自带的
- 用户位置大头针模型
- 监听大头针的点击
- 迷惑点
- 一个大头针模型对应一个大头针视图,根据大头针模型的数据可以让大头针视图展示不同的样子
- 大头针视图包括2部分:
- 那个大头针控件
- 点击大头针出现的弹框(可以控制是否展示)
- 系统自带的大头针视图不能够满足我们需要的样子时,我们可以自定义大头针视图
- 以下两个图要理解
- 这2部分是一个大头针视图
- 这2部分是两个大头针视图
- 这2部分是一个大头针视图
- 代码分析:
-
理解下面各个类的作用:
1. ZHAnnotation 系统自带大头针视图对应的大头针模型 对应大头针视图为: MKAnnotationView 2. ZHDefineAlertAnnotation 自定义大头针视图对应的大头针模型 对应大头针视图为: ZHDefineAlertAnnotationView 3. ZHDefineAlertAnnotationView 自定义大头针视图控件,与MKAnnotationView作对比 4. ZHDefineAlertView 自定义大头针视图子控件 5. ZHDefineDataModel 大头针模型封装的数据模型
-
代码如下:
-
ZHAnnotation类:
//系统自带大头针视图对应的大头针模型 #import <Foundation/Foundation.h> #import <MapKit/MapKit.h> #import "ZHDefineDataModel.h" @interface ZHAnnotation : NSObject<MKAnnotation> /** 坐标位置 */ @property (nonatomic,assign) CLLocationCoordinate2D coordinate; //数据模型 @property (nonatomic,strong) ZHDefineDataModel *defineModel; //记录是否已经显示了(如果显示了就不在显示了) @property (nonatomic, assign, getter = isShowDesc) BOOL showDesc; @end #import "ZHAnnotation.h" @implementation ZHAnnotation -(void)setDefineModel:(ZHDefineDataModel *)defineModel{ _defineModel = defineModel; _coordinate = defineModel.coordinate; } @end
-
ZHDefineAlertAnnotation类:
// 自定义大头针视图对应的大头针模型 #import <Foundation/Foundation.h> #import <MapKit/MapKit.h> #import "ZHDefineDataModel.h" @interface ZHDefineAlertAnnotation : NSObject<MKAnnotation> /** 坐标位置 */ @property (nonatomic,assign) CLLocationCoordinate2D coordinate; //数据模型 @property (nonatomic,strong) ZHDefineDataModel *defineModel; @end #import "ZHDefineAlertAnnotation.h" @implementation ZHDefineAlertAnnotation -(void)setDefineModel:(ZHDefineDataModel *)defineModel{ _defineModel = defineModel; _coordinate = defineModel.coordinate; } @end
-
ZHDefineAlertAnnotationView类:
/* 自定义大头针视图控件,与MKAnnotationView作对比 */ #import <MapKit/MapKit.h> @interface ZHDefineAlertAnnotationView : MKAnnotationView @end #import "ZHDefineAlertAnnotationView.h" #import "ZHDefineAlertView.h" #import "UIView+MJ.h" #import "ZHDefineAlertAnnotation.h" @interface ZHDefineAlertAnnotationView () @property (nonatomic,strong) ZHDefineAlertView *defineAlertView; @end @implementation ZHDefineAlertAnnotationView -(instancetype)initWithAnnotation:(id<MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier{ if (self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier]) { [self setup]; } return self; } //初始化子控件 -(void)setup{ //设置自己子控件的frame ZHDefineAlertView *defineAlertView = [ZHDefineAlertView defineAlertView]; defineAlertView.frame = CGRectMake(-55, -100, 120, 50); [self addSubview:defineAlertView]; self.defineAlertView = defineAlertView; //设置自己的frame self.backgroundColor = [UIColor clearColor]; self.frame = CGRectMake(0, 0, defineAlertView.frame.size.width, defineAlertView.frame.size.height ); } //给自己的子控件传递模型 -(void)setAnnotation:(id<MKAnnotation>)annotation{ [super setAnnotation:annotation]; ZHDefineAlertAnnotation *defineAnno = annotation; self.defineAlertView.defineDataModel = defineAnno.defineModel; } /** * 重要方法!!!!!!!: 当一个view被添加到父控件中,就会调用 */ - (void)didMoveToSuperview{ //缩放动画: 有一些弹簧效果 CAKeyframeAnimation *anim = [CAKeyframeAnimation animation]; anim.keyPath = @"transform.scale"; anim.values = @[@0, @1.5, @1, @1.5, @1]; anim.duration = 0.5; [self.layer addAnimation:anim forKey:nil]; } @end
-
ZHDefineAlertView类:
/* 自定义大头针视图子控件 */ #import <UIKit/UIKit.h> #import "ZHDefineDataModel.h" @interface ZHDefineAlertView : UIView +(instancetype)defineAlertView; @property (nonatomic,strong) ZHDefineDataModel *defineDataModel; @end #import "ZHDefineAlertView.h" @interface ZHDefineAlertView () @property (weak, nonatomic) IBOutlet UIImageView *iconView; @property (weak, nonatomic) IBOutlet UILabel *titleLabel; @property (weak, nonatomic) IBOutlet UILabel *subLabel; @end @implementation ZHDefineAlertView -(void)awakeFromNib{ [super awakeFromNib]; self.backgroundColor = [UIColor clearColor]; } +(instancetype)defineAlertView{ return [[NSBundle mainBundle] loadNibNamed:@"ZHDefineAlertView" owner:nil options:nil].lastObject; } -(void)setDefineDataModel:(ZHDefineDataModel *)defineDataModel{ _defineDataModel = defineDataModel; self.iconView.image = [UIImage imageNamed:defineDataModel.image]; self.titleLabel.text = defineDataModel.title; self.subLabel.text = defineDataModel.desc; } @end
-
ZHDefineDataModel类:
/* 自定义大头针视图对应的数据模型 */ #import <Foundation/Foundation.h> #import <CoreLocation/CoreLocation.h> @interface ZHDefineDataModel : NSObject /** * 标题 */ @property (nonatomic, copy) NSString *title; /** * 描述 */ @property (nonatomic, copy) NSString *desc; /** * 图标 */ @property (nonatomic, copy) NSString *icon; /** * 配图 */ @property (nonatomic, copy) NSString *image; /** * 团购的位置 */ @property (nonatomic, assign) CLLocationCoordinate2D coordinate; @end
-
控制器代码
#import "ViewController.h" #import <MapKit/MapKit.h> #import <CoreLocation/CoreLocation.h> #import "ZHAnnotation.h" #import "ZHDefineAlertAnnotation.h" #import "ZHDefineAlertAnnotationView.h" #import "ZHDefineDataModel.h" @interface ViewController ()<MKMapViewDelegate> @property (weak, nonatomic) IBOutlet MKMapView *mapView; @property (nonatomic,strong) CLLocationManager *locationManager; //自定义大头针视图的模型数组 @property (nonatomic,strong) NSArray *defineDatas; @end @implementation ViewController -(CLLocationManager *)locationManager{ if (_locationManager == nil) { _locationManager = [[CLLocationManager alloc] init]; } return _locationManager ; } -(NSArray *)defineDatas{ if (_defineDatas == nil) { ZHDefineDataModel *tg1 = [[ZHDefineDataModel alloc] init]; tg1.title = @"xxx大饭店"; tg1.desc = @"全场一律15折,会员20折"; tg1.icon = @"category_1"; tg1.image = @"me"; tg1.coordinate = CLLocationCoordinate2DMake(39, 116); ZHDefineDataModel *tg2 = [[ZHDefineDataModel alloc] init]; tg2.title = @"xxx影院"; tg2.desc = @"最新大片:美国队长2,即将上映。。。"; tg2.icon = @"category_5"; tg2.image = @"other"; tg2.coordinate = CLLocationCoordinate2DMake(29, 110); _defineDatas = @[tg1,tg2]; } return _defineDatas ; } - (void)viewDidLoad { [super viewDidLoad]; //请求定位iOS8.0+ [self.locationManager requestWhenInUseAuthorization]; [self.locationManager requestAlwaysAuthorization]; //设置地图代理 self.mapView.delegate = self; } //添加大头针 - (IBAction)addAnno:(id)sender { //根据数据模型添加对应的系统视图对应的大头针模型 for (ZHDefineDataModel *dataModel in self.defineDatas) { ZHAnnotation *anno = [[ZHAnnotation alloc] init]; anno.defineModel = dataModel; [self.mapView addAnnotation:anno]; } } #pragma mark -MKMapViewDelegate /* 该方法中大头针也是循环利用的 调用时刻: 根据大头针模型,展示大头针视图 */ -(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{ //系统自带的大头针视图 if ([annotation isKindOfClass:[ZHAnnotation class]]){ static NSString *ID = @"tuangou"; // 从缓存池中取出可以循环利用的大头针view MKAnnotationView *annoView = [mapView dequeueReusableAnnotationViewWithIdentifier:ID]; if (annoView == nil) { annoView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:ID]; } // 传递模型 annoView.annotation = annotation; //设置图片 ZHAnnotation *anno = annotation; annoView.image = [UIImage imageNamed:anno.defineModel.icon]; return annoView; }else if ([annotation isKindOfClass:[ZHDefineAlertAnnotation class]]){ //自定义的大头针视图 static NSString *ID = @"defAnno"; ZHDefineAlertAnnotationView *defAnnoView = (ZHDefineAlertAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:ID]; if (defAnnoView == nil) { defAnnoView = [[ZHDefineAlertAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:ID]; } // 传递模型 defAnnoView.annotation = annotation; return defAnnoView; }else{//使用户位置大头针 return nil; } } /* 选中一个大头针 */ -(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view{ if ([view isKindOfClass:[ZHDefineAlertAnnotationView class]]) { //点击自定义的大头针视图 #warning 跳转控制器代码 ZHDefineAlertAnnotation *anno = view.annotation; NSLog(@"跳转控制器---%@", anno.defineModel.title); }else{ //点击系统自带的大头针视图 //1.拿到系统自带大头针的模型 ZHAnnotation *anno = view.annotation; if (anno.isShowDesc) return; // 2.删除以前的ZHDefineAlertAnnotation for (id annotation in mapView.annotations) { if ([annotation isKindOfClass:[ZHDefineAlertAnnotation class]]) { [mapView removeAnnotation:annotation]; } else if ([annotation isKindOfClass:[ZHAnnotation class]]) { ZHAnnotation *annof1 = annotation; annof1.showDesc = NO; } } anno.showDesc = YES; // 3.添加新的ZHDefineAlertAnnotation 大头针视图 // 在这颗被点击的大头针上面, 添加一颗用于描述的大头针视图 ZHDefineAlertAnnotation *deAnno = [[ZHDefineAlertAnnotation alloc] init]; deAnno.defineModel = anno.defineModel; [mapView addAnnotation:deAnno]; } } @end
-
-