センタMapプロジェクト
紹介する
地図上にN個の位置がある場合、中間位置の地図上に表示されるサービスです.
期間
2021.09.30 ~ 10.01😇
ぎじゅつ
羽状バニラ
https://github.com/sanghee-dev/Center-Map
YappUltraHardPractice/Sanghee/Practice2/Practice2 at personal/Sanghee-2 · della-padula/YappUltraHardPractice
特長
要求
場所を追加するには:
場所を削除するには、次の手順に従います。
画面
ウェルカムスクリーン
場所の追加
中央マーク
場所の削除
コードの説明
もっと詳しいコードは羽センターで確認してください.
MapViewController
変数、定数宣言
LocationManagerと注記マネージャをインポートします.モノトーンモードで作られているので~.生成されたものにsharedでアクセスします.注記properties傍観者を使用し、値を設定して3つの関数を実行します.また、centerAnnotationでは、位置タグが変更されるたびに、中心タグも変更されます.変更する場合は、以前の中央タグを削除します.したがって、didSetを使用して新しい中央タグを格納すると、古い中央タグが削除されます.以前のタグはdidSetからoldValueにアクセスできます.最後にmapViewを生成します.
class MapViewController: UIViewController {
private let locationManager = LocationManager.shared
private let annotationManager = AnnotationManager.shared
private let mapView = MKMapView()
private var annotations: [MKPointAnnotation] = [] {
didSet {
showAnnotations()
addCenterAnnotation()
zoomMapView()
}
}
private var centerAnnotation: MKPointAnnotation? {
didSet {
if let oldValue = oldValue {
deleteAnnotation(oldValue)
}
}
}
ロングタッチ時の位置値の取得
viewDidLoadになると、ビューにロングタッチジェスチャーを認識する機能が追加されます.長時間タッチした場合はgetCoordinate関数を実行します.この関数は、既存のmapViewで作成したタッチ位置を座標に変換し、annotations配列に追加します.
private func addLongGesture() {
let longGesture = UILongPressGestureRecognizer(target: self, action: #selector(getCoordinate))
view.addGestureRecognizer(longGesture)
}
@objc
private func getCoordinate(_ longGesture: UILongPressGestureRecognizer) {
let touchPoint = longGesture.location(in: mapView)
let coordinate = mapView.convert(touchPoint, toCoordinateFrom: mapView)
addAnnotation(coordinate)
}
位置マーカーを含むマップビューのズームとズーム
まず、タグが1つ未満でない場合、関数は実行されません(タグを追加するとスケールが悪くなります).spaceはviewとのpadding値です.アノテーションでzoomRectという長方形を作成します.次に、MapViewを設定して長方形を表示します.
private func zoomMapView() {
guard annotations.count > 1 else { return }
var zoomRect: MKMapRect = MKMapRect.null
let padding: CGFloat = 50
for annotation in annotations {
let point = MKMapPoint(annotation.coordinate)
let rect = MKMapRect(x: point.x, y: point.y, width: 0.1, height: 0.1)
zoomRect = zoomRect.isNull ? rect : zoomRect.union(rect)
}
mapView.setVisibleMapRect(zoomRect, edgePadding: UIEdgeInsets(top: padding, left: padding, bottom: padding, right: padding), animated: true)
}
起動時にプレイヤー位置を中心に地図を拡大
ユーザ位置はmapViewのuserLocation変数によって取得されます.この位置を中心に拡大します.
func mapView(_ mapView: MKMapView, didUpdate userLocation: MKUserLocation) {
let region = MKCoordinateRegion(center: userLocation.coordinate, span: MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05))
mapView.setRegion(region, animated: true)
}
Utility
LocationManager
中間位置計算モジュールは単独で設計され,Singletonモードを採用した.モノトーンモードとは、特定の用途で1つのオブジェクトのみを生成し、共用したい場合に使用するデザインモードです.sharedという変数を一度作成し、コード全体でLocationManagerを使用します.共有アクセス使用.その後、init関数にprivateを追加して再生成を防止し、外部へのアクセスを阻止します.権限によって要求が異なる.
import CoreLocation
class LocationManager: NSObject, CLLocationManagerDelegate {
static let shared = LocationManager()
private var manager: CLLocationManager = CLLocationManager()
private override init() {
super.init()
manager.delegate = self
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedWhenInUse {
askLocation()
}
}
func askLocation() {
switch manager.authorizationStatus {
case .authorizedAlways: manager.startUpdatingLocation()
case .authorizedWhenInUse: manager.requestAlwaysAuthorization()
case .notDetermined: manager.requestWhenInUseAuthorization()
case .restricted, .denied: break
@unknown default: break
}
}
}
AnnotationManager
AnnotationManagerもモノトーンモードを使用しています.このマネージャはannotations配列を受け入れ、中心位置に戻ります.
import MapKit
import UIKit
class AnnotationManager {
static let shared = AnnotationManager()
private init() {}
func getCenterCoordinate(_ annotations: [MKAnnotation]) -> CLLocationCoordinate2D {
let count = Double(annotations.count)
let latitude = annotations.map({ $0.coordinate }).map({ $0.latitude }).reduce(0, +) / count
let longitude = annotations.map({ $0.coordinate }).map({ $0.longitude }).reduce(0, +) / count
let coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
return coordinate
}
}
Extensions
コードライブラリの自動レイアウト
Snapkitではなくコードライブラリ自動レイアウトが使用されているため、UIViewではレイアウトを指定するアンカーポイントとcenter、centerX、centerYという関数が生成されます.paddingの間隔の場合、デフォルトは0です.次にconstaintsを更新します.この関数では、updateConstraintsメソッドを呼び出す必要があります.実際にneedsUpdateConstraints()が出力されると、trueからfalseに変わることがわかります.
extension UIView {
func anchor(top: NSLayoutYAxisAnchor? = nil,
left: NSLayoutXAxisAnchor? = nil,
...
paddingTop: CGFloat = 0,
paddingLeft: CGFloat = 0,
...) {
translatesAutoresizingMaskIntoConstraints = false
if let top = top {
topAnchor.constraint(equalTo: top, constant: paddingTop).isActive = true
}
if let left = left {
leftAnchor.constraint(equalTo: left, constant: paddingLeft).isActive = true
}
...
updateConstraintsIfNeeded()
}
func center(inView view: UIView, constant: CGFloat = 0) {
translatesAutoresizingMaskIntoConstraints = false
centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: constant).isActive = true
centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: constant).isActive = true
updateConstraintsIfNeeded()
}
...
}
extension CLLocationCoordinate2D
CLLocationCoordinate 2 DはEqtableを採用していないタイプです.Equatableは、プロトコルで値が同じかどうかを比較できます.これらのタイプの値を比較して、同じかどうかを判断したいため、extension==関数が生成されます.
import CoreLocation
extension CLLocationCoordinate2D: Equatable {
public static func == (lhs: CLLocationCoordinate2D, rhs: CLLocationCoordinate2D) -> Bool {
return lhs.latitude == rhs.latitude && lhs.longitude == rhs.longitude
}
}
PrintFn
デバッグ時にのみ出力するためにprint関数を上書きします.objectを出力すると「DEBUG:(object)」と出力され、他の情報と混合することなく出力結果が表示されます.
public func print(_ object: Any) {
#if DEBUG
Swift.print("DEBUG: \(object)")
#endif
}
Reference
この問題について(センタMapプロジェクト), 我々は、より多くの情報をここで見つけました https://velog.io/@leeesangheee/Center-Map-프로젝트テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol