2:使用图片显示大头针视图,并使用自定义大头针模型、
3:自定义弹出视图、
4:适用于顶部title,底部自定义视图 ios9之后
代码部分:
class SecondViewController: UIViewController {
lazy var mapView: MKMapView = {
let mapView = MKMapView(frame: UIScreen.mainScreen().bounds)
mapView.mapType = .Standard
mapView.scrollEnabled = true
mapView.zoomEnabled = true
mapView.showsUserLocation = true
mapView.delegate = self
return mapView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(self.mapView)
addAnnotations()
}
//MARK: 添加大头针
func addAnnotations(){
//创建MKPointAnnotation对象
let pointAnnotation = MKPointAnnotation()
pointAnnotation.coordinate = CLLocationCoordinate2DMake(39, 100)
pointAnnotation.title = "Jack"
pointAnnotation.subtitle = "hua"
self.mapView.addAnnotation(pointAnnotation)
//创建自定义大头针并添加到地图上
let annotatiOnOne= FirstAnnotation(coordinate: CLLocationCoordinate2DMake(39, 115),title:"xxx大饭店",subtitle:"全场一律15折,会员20折")
annotationOne.icOnImage= UIImage(named: "boy")
self.mapView.addAnnotation(annotationOne)
//自定义弹出视图
let calloutAnnotation = SecondAnnotation(coordinate: CLLocationCoordinate2DMake(39, 80))
calloutAnnotation.icon = UIImage(named: "icon_classify_cafe")
calloutAnnotation.rate = UIImage(named: "icon_Movie_Star_rating")
calloutAnnotation.descriptiOnDetail= "This is a nice restaurant!I'm sure you will enjoy here!Come to here,everone!"
self.mapView.addAnnotation(calloutAnnotation)
//使用系统自带附属视图
let detailAnnotation = DetailCalloutAccessoryAnnotation(coordinate: CLLocationCoordinate2DMake(39, 90),title:"Jack")
self.mapView.addAnnotation(detailAnnotation)
}
}
代码分析:
上面代码主要是将地图添加到当前视图控制器视图上,并添加4个大头针到地图上,自定义大头针模型对象代码如下:
//自定义大头针模型
class FirstAnnotation: NSObject,MKAnnotation {
//位置
var coordinate: CLLocationCoordinate2D
//主标题
var title: String?
//副标题
var subtitle: String?
//图片icon
var iconImage: UIImage?
init(coordinate: CLLocationCoordinate2D,title: String,subtitle:String) {
self.coordinate = coordinate
self.title = title
self.subtitle = subtitle
super.init()
}
}
//用于弹出框类型判断模型
class SecondAnnotation: NSObject,MKAnnotation {
//位置
var coordinate: CLLocationCoordinate2D
//左侧icon
var icon: UIImage?
//icon描述
var descriptionDetail: String?
//底部评分视图
var rate: UIImage?
init(coordinate: CLLocationCoordinate2D) {
self.coordinate = coordinate
super.init()
}
}
//弹出视图模型
class SHCalloutAnnotation: NSObject,MKAnnotation{
var coordinate: CLLocationCoordinate2D
init(coordinate: CLLocationCoordinate2D) {
self.coordinate = coordinate
super.init()
}
//左侧icon
var icon: UIImage?
//icon描述
var descriptionDetail: String?
//底部评分视图
var rate: UIImage?
}
//附属视图模型
class DetailCalloutAccessoryAnnotation: NSObject,MKAnnotation {
//位置
var coordinate: CLLocationCoordinate2D
//主标题
var title: String?
//副标题
var subtitle: String?
init(coordinate: CLLocationCoordinate2D,title: String) {
self.coordinate = coordinate
self.title = title
super.init()
}
//官方示例代码使用:在模型中创建大头针视图
class func createViewAnnotationForMapView(mapView:MKMapView, annotation:MKAnnotation) ->MKAnnotationView{
let identifier = "DetailCalloutAccessoryAnnotation"
var annotatiOnView= mapView.dequeueReusableAnnotationViewWithIdentifier(identifier) as? MKPinAnnotationView
if (annotatiOnView== nil){
annotatiOnView= MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
annotationView!.canShowCallout = true
//设置大头针颜色
annotationView!.pinColor = MKPinAnnotationColor.Purple
let backgroundView = UIView(frame: CGRectZero)
backgroundView.backgroundColor = UIColor.redColor()
//添加约束才可以使用自定义视图
let widthCOnstraint= NSLayoutConstraint(item: backgroundView, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 200)
backgroundView.addConstraint(widthConstraint)
let heightCOnstraint= NSLayoutConstraint(item: backgroundView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 200)
backgroundView.addConstraint(heightConstraint)
if #available(iOS 9.0, *) {
//赋值UIImageView直接可以使用
//returnAnnotaionView!.detailCalloutAccessoryView = UIImageView(image: UIImage(named: "icon_classify_cafe"))
//直接赋值UIView,UILabel等视图不行?http://stackoverflow.com/questions/32581049/mapkit-ios-9-detailcalloutaccessoryview-usage 因为我们需要对宽和高做约束
annotationView!.detailCalloutAccessoryView = backgroundView
} else {
print("iOS9以下系统暂时不能够使用!")
}
}
return annotationView!
}
}
接下来,继续看一下视图控制器中的代码,我通过extension实现协议内容:
extension SecondViewController:MKMapViewDelegate{
//显示大头针时调用,注意方法中的annotation参数是即将显示的大头针对象.1)该方法首先显示大头针的时候会调用2)向地图上添加大头针的时候也会调用
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
var returnAnnotaionView:MKAnnotationView?
if !(annotation.isKindOfClass(MKUserLocation)){//根据模型进行分类
if annotation.isKindOfClass(MKPointAnnotation.self){
//MARK:使用系统样式大头针视图和系统大头针模型
let identifier = "MKPinAnnotationView"
var returnAnnotaiOnView= mapView.dequeueReusableAnnotationViewWithIdentifier(identifier)
if (returnAnnotaiOnView== nil){
returnAnnotaiOnView= MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
returnAnnotaionView!.canShowCallout = true
returnAnnotaionView!.calloutOffset = CGPoint(x: 0, y: -10)
returnAnnotaionView!.leftCalloutAccessoryView = UIButton(type: .ContactAdd)
returnAnnotaionView!.rightCalloutAccessoryView = UIButton(type: .DetailDisclosure)
}else{
returnAnnotaionView!.annotation = annotation
}
return returnAnnotaionView
}else if annotation.isKindOfClass(FirstAnnotation.self){
//MARK:使用图片显示大头针视图,并使用自定义大头针模型
returnAnnotaiOnView= SHAnnotationView.annotationViewWith(mapView, reuseIdentifier:"SHAnnotationView")
returnAnnotaionView!.annotation = annotation
return returnAnnotaionView
}else if annotation.isKindOfClass(SecondAnnotation.self){
let identifier = "Annotation"
var returnAnnotaiOnView= mapView.dequeueReusableAnnotationViewWithIdentifier(identifier) as? MKPinAnnotationView
if (returnAnnotaiOnView== nil){
returnAnnotaiOnView= MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
returnAnnotaionView!.pinColor = MKPinAnnotationColor.Green
}
returnAnnotaionView!.annotation = annotation
return returnAnnotaionView
}else if annotation.isKindOfClass(SHCalloutAnnotation.self){
//MARK:自定义弹出视图
returnAnnotaiOnView= SHCalloutAnnotationView.calloutAnnotationViewWith(mapView)
returnAnnotaionView!.annotation = annotation
return returnAnnotaionView
}else if annotation.isKindOfClass(DetailCalloutAccessoryAnnotation.self){
//MARK:适用于顶部title,底部自定义视图 ios9之后
returnAnnotaiOnView= DetailCalloutAccessoryAnnotation.createViewAnnotationForMapView(mapView, annotation: annotation)
returnAnnotaionView!.annotation = annotation
return returnAnnotaionView
}
}
return returnAnnotaionView
}
//选中大头针时触发
func mapView(mapView: MKMapView, didSelectAnnotationView view: MKAnnotationView) {
//点击大头针模型为SecondAnnotation时,添加自定义弹出视图的大头针到地图上。
if let annotation = view.annotation{
if(annotation.isKindOfClass(SecondAnnotation.self)){
let annotation = annotation as! SecondAnnotation
let calloutAnnotaion = SHCalloutAnnotation(coordinate: annotation.coordinate)
calloutAnnotaion.icon = annotation.icon
calloutAnnotaion.rate = annotation.rate
calloutAnnotaion.descriptiOnDetail= annotation.descriptionDetail
mapView.addAnnotation(calloutAnnotaion)
}
}
}
//反选时触发
func mapView(mapView: MKMapView, didDeselectAnnotationView view: MKAnnotationView) {
for annotation in self.mapView.annotations {
if annotation.isKindOfClass(SHCalloutAnnotation.self){
dispatch_async(dispatch_get_main_queue(), {
mapView.removeAnnotation(annotation)
})
}
}
}
}
以及自定义视图部分:
//边距
public let CalloutBorderSpace:CGFloat = 5
//MARK:自定义大头针视图
class SHAnnotationView: MKAnnotationView {
class func annotationViewWith(mapView: MKMapView,reuseIdentifier:String) ->SHAnnotationView{
//从缓存池中取出可以循环利用的大头针view
var annotatiOnView= mapView.dequeueReusableAnnotationViewWithIdentifier(reuseIdentifier) as? SHAnnotationView
if annotatiOnView== nil{
annotatiOnView= SHAnnotationView(annotation: nil, reuseIdentifier:reuseIdentifier)
annotationView?.canShowCallout = true
annotationView?.leftCalloutAccessoryView = UIButton(type: .InfoDark)
annotationView?.rightCalloutAccessoryView = UIButton(type: .DetailDisclosure)
}
return annotationView!
}
override var annotation: MKAnnotation?{
didSet(annotation){
//显示大头针为图片
if let annotatiOnOne= annotation as? FirstAnnotation{
self.image = annotationOne.iconImage
}
}
}
}
//MARK:弹出视图 继承于MKAnnotationView进行显示视图
class SHCalloutAnnotationView: MKAnnotationView{
//#MARK:使用懒加载声明需要的控件属性
lazy var leftIcon:UIImageView = {
let leftIcon = UIImageView()
self.addSubview(leftIcon)
return leftIcon
}()
lazy var detailLabel:UILabel = {
let detailLabel = UILabel(frame: CGRectZero)
detailLabel.lineBreakMode = .ByCharWrapping
detailLabel.fOnt= UIFont.systemFontOfSize(12)
detailLabel.numberOfLines = 0
self.addSubview(detailLabel)
return detailLabel
}()
lazy var rateIcon:UIImageView = {
let rateIcon = UIImageView()
self.addSubview(rateIcon)
return rateIcon
}()
var button:UIButton!
//#MARK: 创建弹出视图
class func calloutAnnotationViewWith(mapView: MKMapView)-> SHCalloutAnnotationView{
let indentifier = "SHCallOutAnnotationView"
var calloutView = mapView.dequeueReusableAnnotationViewWithIdentifier(indentifier) as? SHCalloutAnnotationView
if calloutView == nil{
calloutView = SHCalloutAnnotationView()
calloutView!.backgroundColor = UIColor.grayColor()
}
return calloutView!
}
//#MARK:赋值数据模型显示相应的数据
override var annotation: MKAnnotation?{
didSet(callOutAnnotation){
if let callOutAnnotation = callOutAnnotation as? SHCalloutAnnotation{
self.leftIcon.image = callOutAnnotation.icon
self.leftIcon.frame = CGRect(x: CalloutBorderSpace, y: CalloutBorderSpace, width: callOutAnnotation.icon!.size.width, height: callOutAnnotation.icon!.size.height)
self.detailLabel.text = callOutAnnotation.descriptionDetail
let string:NSString = self.detailLabel.text!
let detailLabelSize = string.boundingRectWithSize(CGSize(width: 200,height: 200), options:.UsesLineFragmentOrigin, attributes: [NSFontAttributeName: self.detailLabel.font], context: nil)
self.detailLabel.frame = CGRect(x: CGRectGetMaxX(self.leftIcon.frame) + CalloutBorderSpace, y:CGRectGetMinY(self.leftIcon.frame), width: detailLabelSize.width, height: detailLabelSize.height)
self.rateIcon.image = callOutAnnotation.rate
self.rateIcon.frame = CGRect(x: CGRectGetMinX(self.detailLabel.frame), y: CGRectGetMaxY(self.detailLabel.frame) + CalloutBorderSpace, width: callOutAnnotation.rate!.size.width, height: callOutAnnotation.rate!.size.height)
self.bounds = CGRect(x: 0, y: 0, width: CGRectGetMaxX(self.detailLabel.frame) + CalloutBorderSpace, height: CGRectGetMaxY(self.rateIcon.frame) + CalloutBorderSpace)
//注意:确定最终的显示位置
self.centerOffset = CGPointMake(0, -self.bounds.size.height)
}
}
}
//#MARK:当弹出视图显示的时候添加缩放动画
override func didMoveToSuperview() {
let animation = CAKeyframeAnimation(keyPath: "transform.scale")
animation.values = [0,1.5,1,1.5,1]
animation.duration = 0.5
self.layer.addAnimation(animation, forKey: nil)
}
}
代码分析:
我们之前已经添加了4个大头针到地图,当显示大头针的时候,会触发mapView(mapView:MKMapView, viewForAnnotation annotation:MKAnnotation)方法获取大头针视图,我们根据所添加的大头针模型进行分类返回对应的大头针视图。
对于显示使用系统样式大头针视图和系统大头针模型、使用图片显示大头针视图,并使用自定义大头针模型、ios9之后出现的附属视图的属性等都很简单,直接看代码就好。主要分析一下是如何实现callout视图的:
首先是添加一个大头针到视图上,当该大头针被点击的时候,添加我们自定义的大头针SecondAnnotation对象,所有数据都是源于原大头针模型,然后会触发mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation)方法,进行添加我们自定义的callout视图。并赋值annotation数据,显示整个视图。
实现效果图如下: