版本记录
版本号 | 时间 |
---|---|
V1.0 | 2020.06.20 星期六 |
前言
MapKit框架直接从您的应用界面显示地图或卫星图像,调出兴趣点,并确定地图坐标的地标信息。接下来几篇我们就一起看一下这个框架。感兴趣的看下面几篇文章。
1. MapKit框架详细解析(一) —— 基本概览(一)
2. MapKit框架详细解析(二) —— 基本使用简单示例(一)
3. MapKit框架详细解析(三) —— 基本使用简单示例(二)
4. MapKit框架详细解析(四) —— 一个叠加视图相关的简单示例(一)
5. MapKit框架详细解析(五) —— 一个叠加视图相关的简单示例(二)
6. MapKit框架详细解析(六) —— 添加自定义图块(一)
7. MapKit框架详细解析(七) —— 添加自定义图块(二)
8. MapKit框架详细解析(八) —— 添加自定义图块(三)
9. MapKit框架详细解析(九) —— 地图特定区域放大和创建自定义地图annotations(一)
10. MapKit框架详细解析(十) —— 地图特定区域放大和创建自定义地图annotations(二)
11. MapKit框架详细解析(十一) —— 自定义MapKit Tiles(一)
12. MapKit框架详细解析(十二) —— 自定义MapKit Tiles(二)
13. MapKit框架详细解析(十三) —— MapKit Overlay Views(一)
源码
1. Swift
首先看下工程组织结构
接着看下sb中的内容
下面就是源码了
1. Park.swift
import MapKit
class Park {
var name: String?
var boundary: [CLLocationCoordinate2D] = []
var midCoordinate = CLLocationCoordinate2D()
var overlayTopLeftCoordinate = CLLocationCoordinate2D()
var overlayTopRightCoordinate = CLLocationCoordinate2D()
var overlayBottomLeftCoordinate = CLLocationCoordinate2D()
var overlayBottomRightCoordinate: CLLocationCoordinate2D {
return CLLocationCoordinate2D(
latitude: overlayBottomLeftCoordinate.latitude,
longitude: overlayTopRightCoordinate.longitude)
}
var overlayBoundingMapRect: MKMapRect {
let topLeft = MKMapPoint(overlayTopLeftCoordinate)
let topRight = MKMapPoint(overlayTopRightCoordinate)
let bottomLeft = MKMapPoint(overlayBottomLeftCoordinate)
return MKMapRect(
x: topLeft.x,
y: topLeft.y,
width: fabs(topLeft.x - topRight.x),
height: fabs(topLeft.y - bottomLeft.y))
}
init(filename: String) {
guard
let properties = Park.plist(filename) as? [String: Any],
let boundaryPoints = properties["boundary"] as? [String]
else { return }
midCoordinate = Park.parseCoord(dict: properties, fieldName: "midCoord")
overlayTopLeftCoordinate = Park.parseCoord(
dict: properties,
fieldName: "overlayTopLeftCoord")
overlayTopRightCoordinate = Park.parseCoord(
dict: properties,
fieldName: "overlayTopRightCoord")
overlayBottomLeftCoordinate = Park.parseCoord(
dict: properties,
fieldName: "overlayBottomLeftCoord")
let cgPoints = boundaryPoints.map { NSCoder.cgPoint(for: $0) }
boundary = cgPoints.map { CLLocationCoordinate2D(
latitude: CLLocationDegrees($0.x),
longitude: CLLocationDegrees($0.y))
}
}
static func plist(_ plist: String) -> Any? {
guard
let filePath = Bundle.main.path(forResource: plist, ofType: "plist"),
let data = FileManager.default.contents(atPath: filePath)
else { return nil }
do {
return try PropertyListSerialization.propertyList(from: data, options: [], format: nil)
} catch {
return nil
}
}
static func parseCoord(dict: [String: Any], fieldName: String) -> CLLocationCoordinate2D {
if let coord = dict[fieldName] as? String {
let point = NSCoder.cgPoint(for: coord)
return CLLocationCoordinate2D(
latitude: CLLocationDegrees(point.x),
longitude: CLLocationDegrees(point.y))
}
return CLLocationCoordinate2D()
}
}
2. Character.swift
import MapKit
// 1
class Character: MKCircle {
// 2
private var name: String?
var color: UIColor?
// 3
convenience init(filename: String, color: UIColor) {
guard let points = Park.plist(filename) as? [String] else {
self.init()
return
}
let cgPoints = points.map { NSCoder.cgPoint(for: $0) }
let coords = cgPoints.map {
CLLocationCoordinate2D(latitude: CLLocationDegrees($0.x), longitude: CLLocationDegrees($0.y))
}
let randomCenter = coords[Int.random(in: 0...3)]
let randomRadius = CLLocationDistance(Int.random(in: 5...39))
self.init(center: randomCenter, radius: randomRadius)
self.name = filename
self.color = color
}
}
3. ParkMapOverlay.swift
import MapKit
class ParkMapOverlay: NSObject, MKOverlay {
let coordinate: CLLocationCoordinate2D
let boundingMapRect: MKMapRect
init(park: Park) {
boundingMapRect = park.overlayBoundingMapRect
coordinate = park.midCoordinate
}
}
4. ParkMapOverlayView.swift
import MapKit
class ParkMapOverlayView: MKOverlayRenderer {
let overlayImage: UIImage
// 1
init(overlay: MKOverlay, overlayImage: UIImage) {
self.overlayImage = overlayImage
super.init(overlay: overlay)
}
// 2
override func draw(_ mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext) {
guard let imageReference = overlayImage.cgImage else { return }
let rect = self.rect(for: overlay.boundingMapRect)
context.scaleBy(x: 1.0, y: -1.0)
context.translateBy(x: 0.0, y: -rect.size.height)
context.draw(imageReference, in: rect)
}
}
5. AttractionAnnotation.swift
import MapKit
// 1
enum AttractionType: Int {
case misc = 0
case ride
case food
case firstAid
func image() -> UIImage {
switch self {
case .misc:
return UIImage(imageLiteralResourceName: "star") // #imageLiteral(resourceName: "star")
case .ride:
return UIImage(imageLiteralResourceName: "ride") //#imageLiteral(resourceName: "ride")
case .food:
return UIImage(imageLiteralResourceName: "food") //#imageLiteral(resourceName: "food")
case .firstAid:
return UIImage(imageLiteralResourceName: "firstaid") //#imageLiteral(resourceName: "firstaid")
}
}
}
// 2
class AttractionAnnotation: NSObject, MKAnnotation {
// 3
let coordinate: CLLocationCoordinate2D
let title: String?
let subtitle: String?
let type: AttractionType
// 4
init(
coordinate: CLLocationCoordinate2D,
title: String,
subtitle: String,
type: AttractionType
) {
self.coordinate = coordinate
self.title = title
self.subtitle = subtitle
self.type = type
}
}
6. AttractionAnnotationView.swift
import MapKit
class AttractionAnnotationView: MKAnnotationView {
// 1
// Required for MKAnnotationView
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
// 2
override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
guard let attractionAnnotation = self.annotation as? AttractionAnnotation else { return }
image = attractionAnnotation.type.image()
}
}
7. ContentView.swift
import SwiftUI
import MapKit
let park = Park(filename: "MagicMountain")
let mapView = MKMapView(frame: UIScreen.main.bounds)
struct MapView: UIViewRepresentable {
func makeUIView(context: Context) -> MKMapView {
let latDelta = park.overlayTopLeftCoordinate.latitude - park.overlayBottomRightCoordinate.latitude
// Think of a span as a tv size, measure from one corner to another
let span = MKCoordinateSpan(latitudeDelta: fabs(latDelta), longitudeDelta: 0.0)
let region = MKCoordinateRegion(center: park.midCoordinate, span: span)
mapView.region = region
mapView.delegate = context.coordinator
return mapView
}
func updateUIView(_ uiView: MKMapView, context: Context) {
}
// Acts as the MapView delegate
class Coordinator: NSObject, MKMapViewDelegate {
var parent: MapView
init(_ parent: MapView) {
self.parent = parent
}
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
if overlay is ParkMapOverlay {
return ParkMapOverlayView(
overlay: overlay,
overlayImage: UIImage(imageLiteralResourceName: "overlay_park"))
} else if overlay is MKPolyline {
let lineView = MKPolylineRenderer(overlay: overlay)
lineView.strokeColor = .green
return lineView
} else if overlay is MKPolygon {
let polygonView = MKPolygonRenderer(overlay: overlay)
polygonView.strokeColor = .magenta
return polygonView
} else if let character = overlay as? Character {
let circleView = MKCircleRenderer(overlay: character)
circleView.strokeColor = character.color
return circleView
}
return MKOverlayRenderer()
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let annotationView = AttractionAnnotationView(annotation: annotation, reuseIdentifier: "Attraction")
annotationView.canShowCallout = true
return annotationView
}
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
}
struct ContentView: View {
@State var mapBoundary = false
@State var mapOverlay = false
@State var mapPins = false
@State var mapCharacterLocation = false
@State var mapRoute = false
var body: some View {
NavigationView {
MapView()
.navigationBarTitle("", displayMode: .inline)
.navigationBarItems(leading:
HStack {
Button(":Bound:") {
self.mapBoundary.toggle()
self.updateMapOverlayViews()
}
.foregroundColor(mapBoundary ? .white : .red)
.background(mapBoundary ? Color.green : Color.clear)
Button(":Overlay:") {
self.mapOverlay.toggle()
self.updateMapOverlayViews()
}
.foregroundColor(mapOverlay ? .white : .red)
.background(mapOverlay ? Color.green : Color.clear)
Button(":Pins:") {
self.mapPins.toggle()
self.updateMapOverlayViews()
}
.foregroundColor(mapPins ? .white : .red)
.background(mapPins ? Color.green : Color.clear)
Button(":Characters:") {
self.mapCharacterLocation.toggle()
self.updateMapOverlayViews()
}
.foregroundColor(mapCharacterLocation ? .white : .red)
.background(mapCharacterLocation ? Color.green : Color.clear)
Button(":Route:") {
self.mapRoute.toggle()
self.updateMapOverlayViews()
}
.foregroundColor(mapRoute ? .white : .red)
.background(mapRoute ? Color.green : Color.clear)
}
)
}
}
func addOverlay() {
let overlay = ParkMapOverlay(park: park)
mapView.addOverlay(overlay)
}
func addAttractionPins() {
// 1
guard let attractions = Park.plist("MagicMountainAttractions") as? [[String: String]] else { return }
// 2
for attraction in attractions {
let coordinate = Park.parseCoord(dict: attraction, fieldName: "location")
let title = attraction["name"] ?? ""
let typeRawValue = Int(attraction["type"] ?? "0") ?? 0
let type = AttractionType(rawValue: typeRawValue) ?? .misc
let subtitle = attraction["subtitle"] ?? ""
// 3
let annotation = AttractionAnnotation(coordinate: coordinate, title: title, subtitle: subtitle, type: type)
mapView.addAnnotation(annotation)
}
}
func addRoute() {
guard let points = Park.plist("EntranceToGoliathRoute") as? [String] else { return }
let cgPoints = points.map { NSCoder.cgPoint(for: $0) }
let coords = cgPoints.map { CLLocationCoordinate2D(
latitude: CLLocationDegrees($0.x),
longitude: CLLocationDegrees($0.y))
}
let myPolyline = MKPolyline(coordinates: coords, count: coords.count)
mapView.addOverlay(myPolyline)
}
func addBoundary() {
mapView.addOverlay(MKPolygon(coordinates: park.boundary, count: park.boundary.count))
}
func addCharacterLocation() {
mapView.addOverlay(Character(filename: "BatmanLocations", color: .blue))
mapView.addOverlay(Character(filename: "TazLocations", color: .orange))
mapView.addOverlay(Character(filename: "TweetyBirdLocations", color: .yellow))
}
func updateMapOverlayViews() {
mapView.removeAnnotations(mapView.annotations)
mapView.removeOverlays(mapView.overlays)
if mapBoundary { addBoundary() }
if mapOverlay { addOverlay() }
if mapPins { addAttractionPins() }
if mapCharacterLocation { addCharacterLocation() }
if mapRoute { addRoute() }
}
}
后记
本篇主要讲述了
Overlay Views
,感兴趣的给个赞或者关注~~~
网友评论