地图系列之三 自定义大头针视图

自定义大头针视图控件

  1. 点击大头针会出现一个弹框显示一些内容,这个弹框的样式是系统自定义的,而且iOS各个系统还会有差异,因此为了统一,需要自定义这个弹框
  2. 思路:
    1. 监听大头针的点击
      1. 在该大头针上面在扎(添加)一颗大的大头针视图
      2. 这个大头针视图需要自定义(ZHDefineAlertAnnotationView)
        1. 继承自MKAnnotationView
        2. 根据需要设置自己的frame/以及内部添加所需控件(ZHDefineAlertView)
        3. 重写setAnnotation拿到数据,给子控件设置数据
      3. 这个自定义大头针视图对应的大头针模型也需要自定义
        1. 自定义一个大头针模型,遵守MKAnnotation协议(ZHDefineAlertAnnotation)
        2. 该模型内部可以搞一个数据源属性,方便存储数据(ZHDefineDataModel)
      4. 一旦添加这个自定义大头针模型,就会到数据源方法viewForAnnotation获取对应的自定义大头针视图
    2. 重写大头针视图数据源方法(viewForAnnotation)
      1. 用户位置大头针模型MKUserLocation,返回nil
      2. 判断是系统自带弹框对应的大头针模型ZHAnnotation
        1. 做相应的数据配置
      3. 判断是自定义弹框对应的大头针模型ZHDefineAlertAnnotation
        1. 自定义大头针视图控件(与系统自带的MKAnnotationView作对比),继承自MKAnnotationViewZHDefineAlertAnnotationView
        2. 这个(ZHDefineAlertAnnotationView)View是一个空白控件,需要根据自己的需要添加子控件,因此从写initWithFrame方法,内部添加子控件
        3. 为了方便使用xib搭建创建了一个ZHDefineAlertView子View
  3. 迷惑点
    1. 一个大头针模型对应一个大头针视图,根据大头针模型的数据可以让大头针视图展示不同的样子
    2. 大头针视图包括2部分:
      1. 那个大头针控件
      2. 点击大头针出现的弹框(可以控制是否展示)
    3. 系统自带的大头针视图不能够满足我们需要的样子时,我们可以自定义大头针视图
    4. 以下两个图要理解
      1. 这2部分是一个大头针视图 图1
      2. 这2部分是两个大头针视图 图1
  4. 代码分析:
    1. 理解下面各个类的作用:

       1. ZHAnnotation
           系统自带大头针视图对应的大头针模型
           对应大头针视图为: MKAnnotationView
       2. ZHDefineAlertAnnotation
           自定义大头针视图对应的大头针模型
           对应大头针视图为: ZHDefineAlertAnnotationView
       3. ZHDefineAlertAnnotationView
           自定义大头针视图控件,与MKAnnotationView作对比
       4. ZHDefineAlertView
           自定义大头针视图子控件
       5. ZHDefineDataModel
           大头针模型封装的数据模型
      
    2. 代码如下:

      1. 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
        
      2. 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
        
      3. 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
        
      4. 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
        
      5. 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
        
      6. 控制器代码

         #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
        

注意:该demo在百度云coderzhong的学习中

Table of Contents