gpt4 book ai didi

ios - MKAnnotation View 转场

转载 作者:行者123 更新时间:2023-11-28 15:08:44 27 4
gpt4 key购买 nike

我有一组要显示在 MapView 上的地点。我创建了一个 MKAnnotationView 来显示一个右键。然后我显示一个 detailView 并通过 segue 传递数据,但它显示错误的位置。我认为我的 selectedAnnotations 有问题。用户一次只能选择一个注释。

全类

import UIKit
import MapKit

class MapViewController: UIViewController, PlacesModelDelegate, CLLocationManagerDelegate {

@IBOutlet weak var mapView: MKMapView!

var places = [Place]()
var model:PlacesModel?
var locationManager:CLLocationManager?
var lastKnownLocation:CLLocation?

var selectedAnnotation: Place?

// MARK: - Lifecycle

override func viewDidLoad() {
super.viewDidLoad()

mapView.delegate = self

// Set map properties
mapView.showsUserLocation = true

// Instantiate location manager
locationManager = CLLocationManager()
locationManager?.delegate = self

// Instantiate places model if it is nil
if model == nil {
model = PlacesModel()
model?.delegate = self
}

// Call get places
model?.getPlaces()

}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

// MARK: - Functions

func plotPins() {

var pinsArray = [MKPointAnnotation]()

// Go through the array of places and plot them
for p in places {

// Create a pin
let pin = MKPointAnnotation()

// Set its properties
pin.coordinate = CLLocationCoordinate2D(latitude: CLLocationDegrees(p.lat), longitude: CLLocationDegrees(p.long))
pin.title = p.name
pin.subtitle = p.getTypeName()

// Add it to the map
mapView.addAnnotation(pin)

// Store the pin in the pinsArray
pinsArray.append(pin)
}

// Center the map
mapView.showAnnotations(pinsArray, animated: true)
}

func displaySettingsPopup() {

// Create alert controller
let alertController = UIAlertController(title: "Couldn't find your location",
message: "Location Services is turned off on your device or the GuideBookApp doesn't have permission to find your location. Please check your Privacy settings to continue.",
preferredStyle: .alert)

// Create settings button action
let settingsAction = UIAlertAction(title: "Settings", style: .default) { (alertAction) in

if let appSettings = URL(string: UIApplicationOpenSettingsURLString) {

UIApplication.shared.open(appSettings, options: [:], completionHandler: nil)

}
}
alertController.addAction(settingsAction)

// Create cancel button action
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alertController.addAction(cancelAction)

// Show the alert
present(alertController, animated: true, completion: nil)

}

// MARK: - Button Handlers

@IBAction func locationButtonTapped(_ sender: UIButton) {

// Check if location services are enabled
if CLLocationManager.locationServicesEnabled() {

// They're enabled, now check the authorization status
let status = CLLocationManager.authorizationStatus()

if status == .authorizedAlways || status == .authorizedWhenInUse {

// Has permission
locationManager?.startUpdatingLocation()

// Center the map on last location
if let actualLocation = lastKnownLocation {
mapView.setCenter(actualLocation.coordinate, animated: true)
}
}
else if status == .denied || status == .restricted {

// Doesn't have permission
// Tell user to check settings
displaySettingsPopup()
}
else if status == .notDetermined {

// Ask the user for permission
locationManager?.requestWhenInUseAuthorization()
}

}
else {
// Locations services are turned off
// Tell user to check settings
displaySettingsPopup()
}

}

// MARK: - PlacesModelDelegate Methods

func placesModel(places: [Place]) {

// Set places property
self.places = places

// Plot the pins
plotPins()
}

// MARK: - CLLocationManagerDelegate Methods

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

let location = locations.last

if let actualLocation = location {

// Create a pin
let pin = MKPointAnnotation()
pin.coordinate = CLLocationCoordinate2D(latitude: actualLocation.coordinate.latitude, longitude: actualLocation.coordinate.longitude)

// Center the map, only if it's the first time locating the user
if lastKnownLocation == nil {
mapView.setCenter(actualLocation.coordinate, animated: true)
}

// Save the pin
lastKnownLocation = actualLocation
}

}

func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {

// See what the user has answered
if status == .denied {

// Tell user that this app doesn't have permission. They can change it in their settings
displaySettingsPopup()
}
else if status == .authorizedWhenInUse || status == .authorizedAlways {

// Permission granted
locationManager?.startUpdatingLocation()
}

}

}

extension MapViewController: MKMapViewDelegate {


func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let identifier = "marker"
var view: MKMarkerAnnotationView

view = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: identifier)
view.canShowCallout = true
view.calloutOffset = CGPoint(x: -5, y: 5)
view.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)

return view
}

func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {

performSegue(withIdentifier: "mapSegue", sender: view)

}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {


let selectedRow = mapView.selectedAnnotations.endIndex

let selectedPlace = places[selectedRow]

let detailModel = DetailModel()
detailModel.place = selectedPlace

let detailVC = segue.destination as! VenueDetailViewController
detailVC.model = detailModel

}
}

地点模型

import UIKit

protocol PlacesModelDelegate {

func placesModel(places:[Place])

}

class PlacesModel: NSObject, FirebaseManagerDelegate {

// Properties
var delegate:PlacesModelDelegate?
var firManager:FirebaseManager?

func getPlaces() {

// Get places from FirebaseManager
if firManager == nil {
firManager = FirebaseManager()
firManager!.delegate = self
}

// Tell firebase manager to fetch places
firManager!.getPlacesFromDatabase()
}

func checkDataVersion() {

// Get version from FirebaseManager
if firManager == nil {
firManager = FirebaseManager()
firManager!.delegate = self
}

firManager!.getVersionFromDatabase()
}

// MARK: - FirebaseManager Delegate Methods

func firebaseManager(places: [Place]) {

// Notify the delegate
if let actualDelegate = delegate {
actualDelegate.placesModel(places: places)
}
}

}

FirebaseManager

import UIKit
import Firebase

@objc protocol FirebaseManagerDelegate {

@objc optional func firebaseManager(places:[Place])
@objc optional func firebaseManager(metaDataFor place:Place)
@objc optional func firebaseManager(imageName:String, imageData:Data)

}

class FirebaseManager: NSObject {

// MARK: - Properties

var ref: FIRDatabaseReference!
var delegate:FirebaseManagerDelegate?

// MARK: - Initializers

override init() {

// Initialize the database reference
ref = FIRDatabase.database().reference()

super.init()
}


// MARK: - Places Functions

func getPlacesFromDatabase() {

// Create an array to store all the places
var allPlaces = [Place]()

// Before we retrieve from Firebase, check cachemanager
if let cachedPlacesDict = CacheManager.getPlacesFromCache() {

// We have data in cache, parse that instead
// Call function to parse places dictionary

allPlaces = parsePlacesFrom(placesDict: cachedPlacesDict)

// Now return the places array
// Dispatch this code to be done on the main thread
DispatchQueue.main.async {

// Notify the delegate
if let actualDelegate = self.delegate {
actualDelegate.firebaseManager?(places: allPlaces)
}
} // End DispatchQueue

return
}


// Retrieve the list of Places from the database
ref.child("places").observeSingleEvent(of: .value, with: { (snapshot) in



let placesDict = snapshot.value as? NSDictionary

// See if data is actually present
if let actualPlacesDict = placesDict {

// We actually have a places dictionary

// Before working with the data, save it into cache
CacheManager.putPlacesIntoCache(data: actualPlacesDict)

// Call function to parse places dictionary
allPlaces = self.parsePlacesFrom(placesDict: actualPlacesDict)

// Now return the places array
// Dispatch this code to be done on the main thread
DispatchQueue.main.async {

// Notify the delegate
if let actualDelegate = self.delegate {
actualDelegate.firebaseManager?(places: allPlaces)
}
} // End DispatchQueue
}

}) // End observeSingleEvent

} // End getForYouFromDatabase



// MARK: - Meta Functions

func getMetaFromDatabase(place:Place) {

// Before fetching from firebase, check cache
if let cachedMetaDict = CacheManager.getMetaFromCache(placeId: place.id) {

// Parse the meta data
parseMetaFrom(metaDict: cachedMetaDict, place: place)

// Notify the delegate the the meta data has been fetched
// Dispatch this code to be done on the main thread
DispatchQueue.main.async {

// Notify the delegate
if let actualDelegate = self.delegate {
actualDelegate.firebaseManager?(metaDataFor: place)
}
} // End DispatchQueue

return
}

ref.child("meta").child(place.id).observe(.value, with: { (snapshot) in

// Get the dictionary from the snapshot
if let metaDict = snapshot.value as? NSDictionary {

// Save data into cache
CacheManager.putMetaIntoCache(data: metaDict, placeId: place.id)

// Parse firebase results
self.parseMetaFrom(metaDict: metaDict, place: place)

// Notify the delegate the the meta data has been fetched
// Dispatch this code to be done on the main thread
DispatchQueue.main.async {

// Notify the delegate
if let actualDelegate = self.delegate {
actualDelegate.firebaseManager?(metaDataFor: place)
}
} // End DispatchQueue

}

}) // End observeSingleEvent

} // End getMetaFromDatabase

func getImageFromDatabase(imageName:String) {

// Get the image

// Check cache first
if let imageData = CacheManager.getImageFromCache(imageName: imageName) {

// Notify the delegate on the main thread
DispatchQueue.main.async {

// Notify the delegate
if let actualDelegate = self.delegate {
actualDelegate.firebaseManager?(imageName: imageName, imageData: imageData)
}
} // End DispatchQueue

return
}

// Create the storage and file path references
let storage = FIRStorage.storage()
let imagePathReference = storage.reference(withPath: imageName)

// Download in memory with a maximum allowed size of 1MB (1 * 1024 * 1024 bytes)
imagePathReference.data(withMaxSize: 1 * 1024 * 1024) { data, error in
if error != nil {
// Uh-oh, an error occurred!

} else if data != nil {

// Data for the image is returned

// Save the image data into cache
CacheManager.putImageIntoCache(data: data!, imageName: imageName)

// Notify the delegate on the main thread
DispatchQueue.main.async {

// Notify the delegate
if let actualDelegate = self.delegate {
actualDelegate.firebaseManager?(imageName: imageName, imageData: data!)
}
} // End DispatchQueue
}
}
}

func closeObserversForPlace(placeId:String) {

// Remove observers from that place node
ref.child("meta").child(placeId).removeAllObservers()
}



// MARK: - Version Functions

func getVersionFromDatabase() {

// Get the version from the database
ref.child("version").observeSingleEvent(of: .value, with: { (snapshot) in

let versionString = snapshot.value as? String

if let databaseVersion = versionString {

let cachedVersion = CacheManager.getVersionFromCache()

if cachedVersion != nil {

// Compare the cached version number to the database version
if databaseVersion > cachedVersion! {

// Remove all cached data
CacheManager.removeAllCachedData()
CacheManager.putVersionIntoCache(version: databaseVersion)
}
}
else {
// Save the database version number to cache
CacheManager.putVersionIntoCache(version: databaseVersion)
}

}

})

}

// MARK: - Helper Functions

func parsePlacesFrom(placesDict:NSDictionary) -> [Place] {

// Declare an array to store the parsed out places
var allPlaces = [Place]()

// Loop through all of the KVPs of the placesDict
for (placeid, placedata) in placesDict {

let placeDataDict = placedata as! NSDictionary

// Create a Place object for each and add it to an array to be returned
let place = Place()

place.id = placeid as! String
place.name = placeDataDict["name"] as! String
place.addr = placeDataDict["address"] as! String
place.lat = placeDataDict["lat"] as! Float
place.long = placeDataDict["long"] as! Float
place.type = PlaceType(rawValue: placeDataDict["type"] as! Int)!
place.cellImageName = placeDataDict["imagesmall"] as! String

place.createDate = placeDataDict["creationDate"] as! Int



// Put this place object into an array for returning
allPlaces += [place]
}

return allPlaces

}

func parseMetaFrom(metaDict:NSDictionary, place:Place) {

place.desc = metaDict["desc"] as! String
place.detailImageName = metaDict["imagebig"] as! String

}

} // End class

最佳答案

好的,这是您开始时必须了解的内容:

此方法 mapView(mapView: MKMapView, annotationView: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) 是通过您点击的 pin 调用的,因此您需要处理您的逻辑从那里。

继续,当 MKAnnotationView 类非常有限并且它的主要子类(annotation)只为您提供基础知识时,您将如何做到这一点:引脚的 coordinates, titlesubtitle... 很简单,有 2 个选项:你要么创建一个继承自它的自定义类,然后在其中添加你的自定义参数,然后因此将能够包含您稍后将用于 map 上每个图钉的相关信息(我认为这可能是您选择的那个,因为它是最简单并且更重要的是,产生较少冗余的那个)您使用来自该点的坐标,然后根据所选点的坐标和您的位置模型进行交叉匹配。这看起来很像以下几行:

func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
for p in places {
let testLocation = CLLocationCoordinate2D(latitude: CLLocationDegrees(p.lat), longitude: CLLocationDegrees(p.long))
if testLocation.latitude == view.annotation!.coordinate.latitude && testLocation.longitude == view.annotation!.coordinate.longitude {
performSegue(withIdentifier: "mapSegue", sender: p)
break
}
}
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let selectedPlace = sender as! Place //Careful with these force unwrapping in the future, I'm just using it here for simplicity but you should always double check them

let detailModel = DetailModel()
detailModel.place = selectedPlace

let detailVC = segue.destination as! VenueDetailViewController
detailVC.model = detailModel
}

如您所见,prepareForSegue 方法几乎保持不变,只是现在它利用了 sender 参数。您在执行 segue.destination as 时也应该小心! VenueDetailViewController 因为将来如果从此 View 添加更多 segue,这可能会由于从其他类发送的意外参数而导致崩溃。

关于ios - MKAnnotation View 转场,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48006378/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com