LeadKit/TIYandexMapUtils/Sources/YandexMapUISettings.swift

136 lines
5.1 KiB
Swift

//
// Copyright (c) 2023 Touch Instinct
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the Software), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
import TIMapUtils
import YandexMapsMobile
open class YandexMapUISettings: BaseMapUISettings<YMKMapView> {
open class UserLocationObjectListener: NSObject, YMKUserLocationObjectListener {
public var tintColor: UIColor {
didSet {
userLocationView?.accuracyCircle.fillColor = tintColor.withAlphaComponent(0.2)
}
}
public var currentLocationIcon: UIImage {
didSet {
updateCurrentLocationIcon()
}
}
private weak var userLocationView: YMKUserLocationView?
public init(tintColor: UIColor, currentLocationIcon: UIImage) {
self.tintColor = tintColor
self.currentLocationIcon = currentLocationIcon
}
// MARK: - YMKUserLocationObjectListener
open func onObjectAdded(with view: YMKUserLocationView) {
self.userLocationView = view
updateCurrentLocationIcon()
view.accuracyCircle.fillColor = tintColor.withAlphaComponent(0.2)
}
open func onObjectRemoved(with view: YMKUserLocationView) {}
open func onObjectUpdated(with view: YMKUserLocationView, event: YMKObjectEvent) {}
private func updateCurrentLocationIcon() {
userLocationView?.arrow.setIconWith(currentLocationIcon)
let style = YMKIconStyle(anchor: CGPoint(x: 0.5, y: 0.5) as NSValue,
rotationType:YMKRotationType.rotate.rawValue as NSNumber,
zIndex: 0,
flat: true,
visible: true,
scale: 1,
tappableArea: nil)
userLocationView?.pin.setIconWith(currentLocationIcon, style: style)
}
}
public weak var userLocationLayer: YMKUserLocationLayer?
public weak var mapKit: YMKMapKit?
public var userLocationObjectListener: UserLocationObjectListener?
public var tintColor: UIColor = .red {
didSet {
userLocationObjectListener?.tintColor = tintColor
}
}
public var showHeadingArrow: Bool = true {
didSet {
userLocationObjectListener?.currentLocationIcon = currentLocationIcon(showHeadingArrow: showHeadingArrow)
}
}
public init(mapKit: YMKMapKit = .sharedInstance()) {
self.mapKit = mapKit
}
open override func apply(to mapView: YMKMapView) {
super.apply(to: mapView)
if showUserLocation {
if userLocationLayer == nil {
userLocationLayer = mapKit?.createUserLocationLayer(with: mapView.mapWindow)
}
let currentLocationIcon = currentLocationIcon(showHeadingArrow: showHeadingArrow)
userLocationObjectListener = UserLocationObjectListener(tintColor: tintColor,
currentLocationIcon: currentLocationIcon)
} else {
userLocationObjectListener = nil
}
userLocationLayer?.setVisibleWithOn(showUserLocation)
userLocationLayer?.setObjectListenerWith(userLocationObjectListener)
let map = mapView.mapWindow.map
map.isZoomGesturesEnabled = isZoomEnabled
map.isTiltGesturesEnabled = isTiltEnabled
map.isRotateGesturesEnabled = isRotationEnabled
}
// MARK: - Subclass override
open func currentLocationIcon(showHeadingArrow: Bool = true) -> UIImage {
let locationDrawingOperation = CurrentLocationDrawingOperation(mainColor: tintColor.cgColor,
borderColor: UIColor.white.cgColor,
showHeadingArrow: showHeadingArrow)
let renderer = UIGraphicsImageRenderer(bounds: locationDrawingOperation.affectedArea())
return renderer.image {
locationDrawingOperation.apply(in: $0.cgContext)
}
}
}