高德地图官方文档:https://lbs.amap.com/api/ios-sdk/guide/draw-on-map/draw-marker
之前那些SDK导入就不做说明了,直接导入后,开始。
看高德地图官方文档基本都是OC语言写的,swift也就没这么详细说明了。
这种高度自定义,用的也是oc自定义,没有给出swift版本的demo出来,所以我们想做到后面这个效果来:
气泡在iOS中又称为callout,它由背景和气泡内容构成,如下图所示:
也就是官方的效果。今天我们就用Swift来实现他了:
(1) 新建自定义气泡类 CustomCalloutViewSwift,继承 UIView。
(2)在类中重写UIView的drawRect方法,绘制弹出气泡的背景,可以自己更改背景颜色。
(3)定义用于显示气泡内容的控件,并添加到SubView中。如上图所示气泡,我们需要一个UIImageView和两个UILabel
(4)在CustomCalloutView.m中给控件传入数据。
import UIKit
class CustomCalloutViewSwift: UIView{
var portraitView : UIImageView!
var subtitleLabel : UILabel!
var titleLabel : UILabel!
//初始化定义气泡的背景
override func draw(_ rect: CGRect) {
drawInContext(context: UIGraphicsGetCurrentContext()!)
self.layer.shadowColor = UIColor.red.cgColor
self.layer.shadowOpacity = 1.0
self.layer.shadowOffset = CGSize.init(width: 0.0, height: 0.0)
}
override init(frame: CGRect) {
super.init(frame: frame)
// self.backgroundColor = UIColor.red
initSubViews()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initSubViews()
fatalError("init(coder:) has not been implemented")
}
func drawInContext(context : CGContext) {
context.setLineWidth(2.0)
context.setFillColor(red: 0.3, green: 0.3, blue: 0.3, alpha: 0.8)
getDrawPath(context: context)
context.fillPath()
}
func getDrawPath(context : CGContext) {
let kArrorHeight = 10
let rect = self.bounds
let radius = 6.0
let minx = rect.minX
let midx = rect.midX
let maxx = rect.maxX
let miny = rect.minY
let maxy = rect.maxY - 10
context.move(to: CGPoint.init(x: midx + CGFloat(kArrorHeight), y: maxy))
context.addLine(to: CGPoint.init(x: midx, y: maxy + CGFloat(kArrorHeight)))
context.addLine(to: CGPoint.init(x: midx - CGFloat(kArrorHeight), y: maxy))
context.addArc(tangent1End: CGPoint.init(x: minx, y: maxy), tangent2End: CGPoint.init(x: minx, y: miny), radius: CGFloat(radius))
context.addArc(tangent1End: CGPoint.init(x: minx, y: minx), tangent2End: CGPoint.init(x: maxx, y: miny), radius: CGFloat(radius))
context.addArc(tangent1End: CGPoint.init(x: maxx, y: miny), tangent2End: CGPoint.init(x: maxx, y: maxx), radius: CGFloat(radius))
context.addArc(tangent1End: CGPoint.init(x: maxx, y: maxy), tangent2End: CGPoint.init(x: midx, y: maxy), radius: CGFloat(radius))
context.closePath();
}
//初始化定义气泡的内容
func initSubViews() {
backgroundColor = UIColor.clear
let kPortraitMargin = 5.0
let kPortraitWidth = 70.0
let kPortraitHeight = 50.0
let kTitleWidth = 120.0
let kTitleHeight = 20.0
// 添加图片,即商户图
portraitView = UIImageView.init(frame: CGRect.init(x: kPortraitMargin, y: kPortraitMargin, width: kPortraitWidth, height: kPortraitHeight))
portraitView.backgroundColor = UIColor.black
addSubview(portraitView)
// 添加标题,即商户名
titleLabel = UILabel.init(frame: CGRect.init(x: kPortraitMargin * 2 + kPortraitWidth, y: kPortraitMargin, width: kTitleWidth, height: kTitleHeight))
titleLabel.font = UIFont.systemFont(ofSize: 14)
titleLabel.textColor = UIColor.white
titleLabel.text = "我是商户名"
addSubview(titleLabel)
// 添加副标题,即商户地址
subtitleLabel = UILabel.init(frame: CGRect.init(x: kPortraitMargin * 2 + kPortraitWidth, y: kPortraitMargin * 2 + kTitleHeight, width: kTitleWidth, height: kTitleHeight))
subtitleLabel.font = UIFont.systemFont(ofSize: 12)
subtitleLabel.textColor = UIColor.lightGray
subtitleLabel.text = "我是商户地址"
addSubview(subtitleLabel)
}
//给控件传入数据
func setTitle(title : NSString) {
titleLabel.text = title as String;
}
func setSubtitle(subtitle : NSString) {
subtitleLabel.text = subtitle as String;
}
func setImage(image : UIImage) {
portraitView.image = image;
}
///导航事件
@objc func guidBtnAction() {
// self.guideActionCallBack?()
}
func guideActionCallBack() {
print("click btn")
}
}
以上就是自定义气泡的全部过程,但是为了在点击标注时,弹出自定义的气泡,还需要。步骤如下:
(1) 新建类CustomAnnotationViewSwift,继承MAAnnotationView或MAPinAnnotationView。若继承MAAnnotationView,则需要设置标注图标;若继承MAPinAnnotationView,使用默认的大头针标注
(2) 在CustomAnnotationViewSwift中定义自定义气泡属性,可修改calloutView属性
(3) 重写选中方法setSelected。选中时新建并添加calloutView,传入数据;非选中时删除calloutView。
import UIKit
class CustomAnnotationViewSwift: MAAnnotationView {
//定义气泡背景与内容对象
var calloutView : CustomCalloutViewSwift?
var content : String?
//重写选中效果
override func setSelected(_ selected: Bool, animated: Bool) {
if self.isSelected == selected{
return;
}
if selected {
if calloutView == nil {
calloutView = CustomCalloutViewSwift.init(frame: CGRect.init(x: 0, y: 0, width: 200, height: 70))
calloutView!.center = CGPoint.init(x: bounds.width/2 + calloutOffset.x, y: -calloutView!.bounds.height/2 + calloutOffset.y)
}
//传入数据给气泡内容
let image = UIImage.init(named: "MyImageName")
calloutView?.setImage(image: image!)
calloutView?.setTitle(title: "我是商家名")
calloutView?.setSubtitle(subtitle: "我是商家地址")
addSubview(calloutView!)
} else {
calloutView!.removeFromSuperview()
}
super.setSelected(selected, animated: animated)
}
func setContent(content : String){
self.content = content
}
}
定义了上面两个类,我们直接在地图上调用就好了,
func mapView(_ mapView: MAMapView!, viewFor annotation: MAAnnotation!) -> MAAnnotationView! {
//MAPointAnnotation,自定义POI点数据,参考demo河马
if annotation is MAPointAnnotation {
let customReuseIndetifier: String = "customReuseIndetifier"
//从复用内存池中获取制定复用标识的annotation view,自定义气泡样式CustomAnnotationView
// var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: customReuseIndetifier) as? CustomAnnotationView
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: customReuseIndetifier) as? CustomAnnotationViewSwift
if annotationView == nil {
annotationView = CustomAnnotationViewSwift.init(annotation: annotation, reuseIdentifier: customReuseIndetifier)
//是否允许弹出callout
annotationView?.canShowCallout = false
///添加到地图时是否使用下落动画效果
// annotationView!.animatesDrop = false
///是否支持拖动
annotationView?.isDraggable = true
///弹出框默认位于view正中上方,可以设置calloutOffset改变view的位置,正的偏移使view朝右下方移动,负的朝左上方,单位是屏幕坐标
annotationView?.calloutOffset = CGPoint.init(x: 0, y: -5)
}
let wellBlueState = UIImage(named: "restaurant")
annotationView?.image = wellBlueState
//背景颜色,透明
annotationView?.backgroundColor = Theme.transparent
annotationView?.frame = CGRect(x: 0, y: 0, width: 20, height: 20)
// annotationView?.portrait = UIImage.init(named: "login")
// annotationView?.name = "河马"
return annotationView
}
return nil
}
自定义调用:var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: customReuseIndetifier) as? CustomAnnotationViewSwift
运行程序,效果如下: