-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathVehicleAnnotationView.swift
113 lines (88 loc) · 3.4 KB
/
VehicleAnnotationView.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.
import UIKit
import MapKit
import Foundation
private typealias Constants = MapViewController.Constants.Pin
public final class VehicleAnnotationView: MKAnnotationView {
private let label = UILabel()
private let roundedRectangle = RoundedRectangleWithArrow()
// MARK: - Init
public init(annotation: VehicleAnnotation, reuseIdentifier: String?) {
super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
self.frame = CGRect(origin: .zero, size: Constants.imageSize)
self.isDraggable = false
self.canShowCallout = false
self.roundedRectangle.frame = self.frame
self.addSubview(self.roundedRectangle)
self.addSubview(self.label)
self.updateImage()
self.updateLabel()
}
@available(*, unavailable)
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - Set vehicle location
public func setVehicleAnnotation(_ annotation: VehicleAnnotation) {
self.annotation = annotation
self.updateImage()
self.updateLabel()
}
// MARK: Update image
public func updateImage() {
guard let annotation = self.annotation as? VehicleAnnotation else {
return
}
// We could decrease number of calls to 'setNeedsDisplay' by comparing
// new color and angle to previous values. But since we refresh vehicle
// locations every X seconds (not frames) that would not save a lot energy
//
// If you change this code, then remember to check what happens when we show
// alert (all annotation go grey -> do they recover without 'setNeedsDisplay'?).
self.roundedRectangle.tintColor = annotation.line.annotationColor
self.roundedRectangle.angle = annotation.angle
self.roundedRectangle.setNeedsDisplay()
}
// MARK: Update label
private static let textAttributes = TextAttributes(style: .body,
color: .white,
alignment: .center)
public func updateLabel() {
guard let annotation = self.annotation as? VehicleAnnotation else {
return
}
self.label.attributedText = NSAttributedString(
string: annotation.line.name,
attributes: Self.textAttributes
)
let imageSize = Constants.imageSize
let size = self.label.intrinsicContentSize
let origin = CGPoint(x: (imageSize.width - size.width) / 2.0,
y: (imageSize.height - size.height) / 2.0)
self.label.frame = CGRect(origin: origin, size: size)
}
}
// MARK: - RoundedRectangleWithArrow
private class RoundedRectangleWithArrow: UIView {
var angle: CGFloat = 0.0 {
didSet {
self.transform = CGAffineTransform(rotationAngle: self.angle.rad)
}
}
override init(frame: CGRect) {
super.init(frame: frame)
self.layer.allowsEdgeAntialiasing = true
self.backgroundColor = UIColor.clear
}
@available(*, unavailable)
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func draw(_ rect: CGRect) {
StyleKit.drawVehicleAnnotation(frame: self.bounds,
color: self.tintColor ?? .black,
resizing: .aspectFit)
}
}