Hello All,
This is my first question here, so please be lenient ;)
I'm trying to add add circular (MKCircle) annotations for all of these model objects in my code instead of adding every of them with coordinations. Here is my code:
let locationManager = CLLocationManager()
struct Szczyt {
let name: String
let opis: String
let lattitude: CLLocationDegrees
let longtitude: CLLocationDegrees
var coordinate: CLLocationCoordinate2D {
.init(latitude: lattitude, longitude: longtitude)
// here Im trying to create var for this property to set it for all objects
}
}
@IBOutlet weak var mapView: MKMapView!
@IBAction func mapTypeSegmentSelected(_ sender: UISegmentedControl) {
switch sender.selectedSegmentIndex {
case 0:
mapView.mapType = .standard
case 1:
mapView.mapType = .satellite
default:
mapView.mapType = .hybrid
}
}
let circles = szczyty.map {
MKCircle(center: $0.coordinate, radius: 100)
//here I got - Cannot use instance member 'szczyty' within property initializer; property initializers run before 'self' is available
}
let szczyty = [Szczyt(name: "one", describtion: "describtion one", lattitude: 50.333061725039226, longtitude: 16.708595782487315),
Szczyt(name: "Two", describtion: "Describtion two", lattitude: 50.444874478583854, longtitude: 20.896341184611302),
Szczyt(name: "Three", describtion: "Describiton three", lattitude: 50.555134079897516, longtitude: 15.884675411850157)]
Can someone can give me a tip or advice how to solve this? Once again - Im trying to set MKCircle for all of the objects in szczyty. Thank you in advance for your help.
In the next steps I would like to detect if user is in those circles by setting 'distance(from:)' method to determinate user location between circle and user location. Than user should have an option to check in in specified area. Also if you would have any tips and advices what to use to do it, I'd be very thankful.
Paweł
Post
Replies
Boosts
Views
Activity
Hello,
I'm learning swift now, so this is my second question here :) I'm creating the app with some annotations on the map. I've added MKCircles in radius 200m from the annotation. This should be a radius in which user can check-in and save his loacation. Can I use distance(from:)to do it?
In general I'm looking for some tips/advices how to set this check in (Could be check-in button inside the annotation view) that saves user location if user is in radius 200m from the annotation. The check-in should be connected to the name and describtion of the annotation (sczyt.name and szczyt.opis), and the annotation name should be saved in a table view "Zdobyte Szczyty", which is another tab bar view in the app. My mainstoryboard looks like this:
There is a Map controller and Zdobyte Szczyty controller. so I would like to save location only if in radius 200m from annotation as annotation name (szczyt.name) and describtion (szczyt.opis) in table view, which is based in Zdobyte Szczyty viewcontroller.
Here is my map viewcontroller.swift:
import UIKit
import MapKit
class ViewController: UIViewController, MKMapViewDelegate{
let locationManager = CLLocationManager()
struct Szczyt {
let name: String
let opis: String
let lattitude: CLLocationDegrees
let longtitude: CLLocationDegrees
var coordinate: CLLocationCoordinate2D {
.init(latitude: lattitude, longitude: longtitude)
}
}
@IBOutlet weak var mapView: MKMapView!
@IBAction func mapTypeSegmentSelected(_ sender: UISegmentedControl) {
switch sender.selectedSegmentIndex {
case 0:
mapView.mapType = .standard
case 1:
mapView.mapType = .satellite
default:
mapView.mapType = .hybrid
}
}
private(set) var circles: [MKCircle]!
let szczyty = [Szczyt(name: “one”, opis: “describtion”, lattitude: 50.825061725039226, longtitude: 16.908595782487315),
Szczyt(name: “two, opis: “describtion”, lattitude: 50.223874478583854, longtitude: 20.996341184611302),
Szczyt(name: “three”, opis: “describtion”, lattitude: 50.756134079897516, longtitude: 15.984675411850157)]
override func viewDidLoad() {
super.viewDidLoad()
checkLocationServices()
znajdzSzczytyNaMapie(szczyty)
circles = szczyty.map {
MKCircle(center: $0.coordinate, radius: 200)
}
mapView.addOverlays(circles!)
mapView.delegate = self
}
func checkLocationServices() {
if CLLocationManager.locationServicesEnabled() {
checkLocationAuthorization()
} else {
// Show alert letting the user know they have to turn this on.
}
}
func checkLocationAuthorization() {
switch CLLocationManager.authorizationStatus() {
case .authorizedWhenInUse:
mapView.showsUserLocation = true
case .denied: // Show alert telling users how to turn on permissions
break
case .notDetermined:
locationManager.requestWhenInUseAuthorization()
mapView.showsUserLocation = true
case .restricted: // Show an alert letting them know what’s up
break
case .authorizedAlways:
break
}
}
func znajdzSzczytyNaMapie(_ szczyty: [Szczyt]) {
for szczyt in szczyty {
let annotations = MKPointAnnotation()
annotations.title = szczyt.name
annotations.subtitle = szczyt.opis
annotations.coordinate = CLLocationCoordinate2D(latitude:
szczyt.lattitude, longitude: szczyt.longtitude)
mapView.addAnnotation(annotations)
}
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
guard !(annotation is MKUserLocation) else { return nil }
let annotationView = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: "MyMarker")
switch annotation.title!! {
case “one”:
annotationView.markerTintColor = UIColor(red: 0.86, green: 0.99, blue: 0.79, alpha: 1.00)
annotationView.glyphImage = UIImage(named: "bald")
case “two”:
annotationView.markerTintColor = UIColor(red: 0.80, green: 0.98, blue: 0.73, alpha: 1.00)
annotationView.glyphImage = UIImage(named: "bear")
case “three”:
annotationView.markerTintColor = UIColor(red: 0.73, green: 0.98, blue: 0.68, alpha: 1.00)
annotationView.glyphImage = UIImage(named: "spruces")
}
return annotationView
}
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
let circleRenderer = MKCircleRenderer(overlay: overlay)
circleRenderer.strokeColor = UIColor.green
circleRenderer.fillColor = UIColor.green
circleRenderer.alpha = 0.3
circleRenderer.lineWidth = 1.0
return circleRenderer
}
}
Here is my ZdobyteSzczyty view controller:
import UIKit
import SwiftUI
class Zdobyte_ViewController: UIViewController {
struct ContentView: View {
var body: some View {
Text("Test viewcontroller gór") //this is not working
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
Hello,
I'm looking for help with annotationView. What I'm going to do is to have already added icons in annotations, but when Im going to tap the annotation (icon) I would like to see the button in annotation view frame, as in this:
After I click it I would like to see this white frame and uibutton:
I was looking for help in old discussion, but did notg found an answer: UIButton in AnnotationView - How to keep icon and button
Here is my viedidload:
super.viewDidLoad()
mapView.register(MKMarkerAnnotationView.self, forAnnotationViewWithReuseIdentifier: "identifier") \\ important part
checkLocationServices()
znajdzSzczytyNaMapie(szczyty)
circles = szczyty.map {
MKCircle(center: $0.coordinate, radius: 100)
}
mapView.addOverlays(circles!)
mapView.delegate = self
}
Here in viewdidload I've added mapView.register(MKMarkerAnnotationView.self, forAnnotationViewWithReuseIdentifier: "identifier") to viewdidload to register indentifier.
Here is the rest of the code:
guard !(annotation is MKUserLocation) else { return nil }
//let annotationView = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: "MyMarker")
let identifier = "identifier"
//guard let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKMarkerAnnotationView else { return nil }
guard let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier, for: annotation) as? MKMarkerAnnotationView else { return nil }
let btn = UIButton(type: .detailDisclosure)
annotationView.rightCalloutAccessoryView = btn
switch annotation.title!! {
ase "Turbacz":
annotationView.markerTintColor = UIColor(red: 0.86, green: 0.99, blue: 0.79, alpha: 1.00)
annotationView.glyphImage = UIImage(named: "bald")
case "example":
annotationView.markerTintColor = UIColor(red: 0.80, green: 0.98, blue: 0.73, alpha: 1.00)
annotationView.glyphImage = UIImage(named: "bear")
default:
annotationView.markerTintColor = UIColor.green
annotationView.glyphImage = UIImage(named: "gora")
}
return annotationView
}
But Still I got this:
Hello All,
I have an app, which is playing url mp3 audio with two image buttons - play and stop. Now I would like to improve it a little bit. I have two .png images (play.png and pause.png) right now and I would like them to change with each other with a tap depending on whether the stream is on or off. Any ideas how to make it? Here is my code:
import UIKit
import AVKit
import MediaPlayer
class ViewController: UIViewController, AVAudioPlayerDelegate {
var player : AVPlayer!
var dict = NSDictionary()
@IBAction func playButtonPressed(_ sender: UIButton){
let url = "https://stream.com/radio.mp3"
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [.mixWithOthers, .allowAirPlay])
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, options: [])
print("Playback OK")
try AVAudioSession.sharedInstance().setActive(true)
print("Session is Active")
} catch {
print(error)
}
player = AVPlayer(url: URL(string: url)!)
player.volume = 1.0
player.rate = 1.0
player.play()
}
@IBAction func stopButtonStopped(sender: UIButton) {
player.pause()
}
Hello,
First of all, I dont know if I'm asking for too much.
I'm new in parsing API data in Swift. What I'm trying to do is to show in my two labels and UIImageView (or maybe there is other way to show album cover from external url) data from nowplaying api on my internet radio station.
Here how it is gonna look like in Main.storyboard:
So far I've tried couple of solutions, but I've stuck on parsing step. Here is my code:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
overrideUserInterfaceStyle = .light
setupRemoteCommandCenter()
//Radio API endpoint
let urlString = "https://admin.radiopromil.online/api/nowplaying_static/radio_promil.json"
let url = URL(string: urlString)
guard url != nil else {
return
}
let session = URLSession.shared
let dataTask = session.dataTask(with: url!) { (data, response, error) in
if error == nil && data != nil {
let decoder = JSONDecoder()
do {
let radio = try decoder.decode(radioAPI.self, from: data!)
print(radio)
DispatchQueue.main.async {
self.title.text = ????
self.artist.text = ????
}
}
catch {
print("Error Parsing JSON")
}
}
}
dataTask.resume()
}
}
So far I removed everything from radioAPI.swift. I
've got two API endpoint:
This one is static JSON https://admin.radiopromil.online/api/nowplaying_static/radio_promil.json
This one is standard API: https://admin.radiopromil.online/api/nowplaying/radio_promil
To sum up: I would like to parse data from API (now_playing: artist, title and cover art url) into two labels and UIImageView.
Data in API is changing when next song is playing.
Thank you in advance for your help.
Hello,
I try to fetch data from my API every 5 seconds. I did this code, but it does not work. Any ideas what I'm doing wrong?
let urlString = "https://radio.app/api/nowplaying/radio_x"
let url = URL(string: urlString)!
let session = URLSession.shared
let dataTask = session.dataTask(with: url) { data, response, error in
if let error = error {
print(error)
return
}
guard let data = data else {
print("data is nil")
return
}
let decoder = JSONDecoder()
do {
let radio = try decoder.decode(RadioAPI.self, from: data)
print(radio)
DispatchQueue.main.asyncAfter(deadline: .now() + 5, execute: {
//this is the line that I've added DispatchQueue.main.asyncDispatchQueue.main.asyncAfter insted of standard
self.songtitle.text = radio.nowPlaying.song.title
self.artist.text = radio.nowPlaying.song.artist
//albumcover art section
if let artUrl = URL(string: radio.nowPlaying.song.art) {
//I need to load an image from `artUrl`
let imageDatatask = session.dataTask(with: artUrl) { imageData, imageResponse, imageError in
if let error = error {
print(error)
return
}
guard let imageData = imageData else {
print("image_data is nil")
return
}
//let albumArt = UIImage(data: imageData)
DispatchQueue.main.async {
let albumArt = UIImage(data: imageData)
let albumView = UIImageView(image: albumArt)
}
}
imageDatatask.resume()
}
})
}
catch {
print("Error Parsing JSON: \(error)")
}
}
dataTask.resume()
}
Hello,
I've implemented two functions in View controller (setupRemoteTransportControls() and setupNowPlaying()) and added one function to AppDelegate, but I'm still unable to see background audio controls of my app on the lock screen and also audio interruption function isn't working. This is the live stream from url, as you can spot on in the code. In the general settings I have added background playing:
What I would like to do is to print on the Remote Command Center artist, title and albumArt, but but i was stuck just displaying the command center. I attach link my code on github, because it is too many characters to paste it: https://github.com/pawelzet/promil_new/blob/main/ViewController.swift
Here is AppDelegate func that I've added:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
application.beginReceivingRemoteControlEvents()
// Override point for customization after application launch.
return true
}
I'm parsing some data from my API and I would like to show artist and title in title section of MPMediaItemPropertyTitle and the album art. Right now I can print a string, as you can spot in the code below, but I would like to print the API data, as I'm doing it in the labels. Thank you in advance for your help. Here is my code:
import UIKit
import AVKit
import MediaPlayer
class ViewController: UIViewController, AVAudioPlayerDelegate {
var player : AVPlayer!
var dict = NSDictionary()
@IBOutlet weak var artist: UILabel!
@IBOutlet weak var songtitle: UILabel!
@IBOutlet weak var artUrl: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
overrideUserInterfaceStyle = .light
setupRemoteTransportControls()
requestNowPlaying()
setupNowPlaying()
addInterruptionsObserver()
}
[...]
//There is parsing section [...]
DispatchQueue.main.async {
self.songtitle.text = radio.nowPlaying.song.title
self.artist.text = radio.nowPlaying.song.artist
self.playlist.text = radio.nowPlaying.playlist
//albumcover art section
if let artUrl = URL(string: radio.nowPlaying.song.art),
artUrl != self.songArtUrl {
//Loading image from `artUrl`
let imageDatatask = session.dataTask(with: artUrl) { imageData, imageResponse, imageError in
if let imageError = imageError {
print(imageError)
return
}
guard let imageData = imageData else {
print("image_data is nil")
return
}
DispatchQueue.main.async {
self.songArtUrl = artUrl
let albumArt = UIImage(data: imageData)
self.artUrl.image = albumArt
}
}
imageDatatask.resume()
}
[...]
//here is some code with adding remote controls
[...]
func setupNowPlaying() {
// Define Now Playing Info
var nowPlayingInfo = [String : Any]()
nowPlayingInfo[MPMediaItemPropertyTitle] = "Here I would like to print artist + title"
nowPlayingInfo[MPMediaItemPropertyArtist] = "My name as string - nothing to change"
if let image = UIImage(named: "Deault_albumart") { //Here I would like to add image from API
nowPlayingInfo[MPMediaItemPropertyArtwork] = MPMediaItemArtwork(boundsSize: image.size) { size in
return image
}
}
nowPlayingInfo[MPNowPlayingInfoPropertyIsLiveStream] = true
MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
}
Hello,
I would like to store, save users data inside the app (Best option to store it in the cloud) with location the user reach. The loaction check in point on the map is within radius 100 meters. So the thing I would like to do is to show as a list in the second viewcontroller Zdobyte Szczyty, names of the locations sczyt.name from the first ViewController (the one with the map) that user reached (clicked with a button to check in). I thought about adding a button to the annotation view, which should do the check in if the user is in this radius - but it does not show me the button, just pin. Here is my code:
import UIKit
import MapKit
class ViewController: UIViewController, MKMapViewDelegate{
let locationManager = CLLocationManager()
struct Szczyt {
let name: String
let opis: String
let lattitude: CLLocationDegrees
let longtitude: CLLocationDegrees
var coordinate: CLLocationCoordinate2D {
.init(latitude: lattitude, longitude: longtitude)
}
}
@IBOutlet weak var mapView: MKMapView!
@IBAction func mapTypeSegmentSelected(_ sender: UISegmentedControl) {
switch sender.selectedSegmentIndex {
case 0:
mapView.mapType = .standard
case 1:
mapView.mapType = .satellite
default:
mapView.mapType = .hybrid
}
}
private(set) var circles: [MKCircle]!
let szczyty = [Szczyt(name: "one", opis: "describtion", lattitude: 53.865061725039226, longtitude: 17.708595782487315),
Szczyt(name: "two", opis: "describtion2", lattitude: 55.893874478583854, longtitude: 24.896341184611302),
Szczyt(name: "Skrzyczne", opis: "describtion3", lattitude: 49.685059170137386, longtitude: 19.030076144463138)]
override func viewDidLoad() {
super.viewDidLoad()
mapView.register(MKMarkerAnnotationView.self, forAnnotationViewWithReuseIdentifier: "identifier")
checkLocationServices()
znajdzSzczytyNaMapie(szczyty)
circles = szczyty.map {
MKCircle(center: $0.coordinate, radius: 100)
}
mapView.addOverlays(circles!)
mapView.delegate = self
}
func checkLocationServices() {
if CLLocationManager.locationServicesEnabled() {
checkLocationAuthorization()
} else {
// Show alert letting the user know they have to turn this on.
}
}
func checkLocationAuthorization() {
switch CLLocationManager.authorizationStatus() {
case .authorizedWhenInUse:
mapView.showsUserLocation = true
case .denied: // Show alert telling users how to turn on permissions
break
case .notDetermined:
locationManager.requestWhenInUseAuthorization()
mapView.showsUserLocation = true
case .restricted: // Show an alert letting them know what’s up
break
case .authorizedAlways:
break
}
}
func znajdzSzczytyNaMapie(_ szczyty: [Szczyt]) {
for szczyt in szczyty {
let annotations = MKPointAnnotation()
annotations.title = szczyt.name
annotations.subtitle = szczyt.opis
annotations.coordinate = CLLocationCoordinate2D(latitude:
szczyt.lattitude, longitude: szczyt.longtitude)
mapView.addAnnotation(annotations)
}
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
guard !(annotation is MKUserLocation) else { return nil }
//let annotationView = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: "MyMarker")
let identifier = "identifier"
//guard let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKMarkerAnnotationView else { return nil }
guard let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier, for: annotation) as? MKMarkerAnnotationView else { return nil }
let btn = UIButton(type: .detailDisclosure)
annotationView.rightCalloutAccessoryView = btn
switch annotation.title!! {
case "one":
annotationView.markerTintColor = UIColor(red: 0.86, green: 0.99, blue: 0.79, alpha: 1.00)
annotationView.glyphImage = UIImage(named: "one_pic")
case "two":
annotationView.markerTintColor = UIColor(red: 0.80, green: 0.98, blue: 0.73, alpha: 1.00)
annotationView.glyphImage = UIImage(named: "two_pic"")
case "Skrzyczne":
annotationView.markerTintColor = UIColor(red: 0.02, green: 0.61, blue: 0.69, alpha: 1.00)
annotationView.glyphImage = UIImage(named: "three_pic"")
default:
annotationView.markerTintColor = UIColor.green
annotationView.glyphImage = UIImage(named: "default")
}
return annotationView
}
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
let circleRenderer = MKCircleRenderer(overlay: overlay)
circleRenderer.strokeColor = UIColor.green
circleRenderer.fillColor = UIColor.green
circleRenderer.alpha = 0.3
circleRenderer.lineWidth = 1.0
return circleRenderer
}
}
This is my Zdobyte Szczyty viewcontroller:
import UIKit
import SwiftUI
class Zdobyte_ViewController: UIViewController {
struct ContentView: View {
var body: some View {
Text("Test viewcontroller gór")
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
Here is the button view I would like to have with the pin image, but now it only shows the pin with the image:
This is how my viewcontrollers view looks like:
Hello,
I have 25 annotations on map. When user tap on each annotation it shows Title and description of the annotation with the buttons (rightCalloutAccessoryView). I would like this button to open second VC called SecondController, ThirdController etc. . Normally I do it with this code:
guard let vc = storyboard?.instantiateViewController(withIdentifier: "second_vc") as? SecondController else {
return
}
present(vc, animated: true)
}
But since the button is in the Annotation I cant put it in IBAction. Also I Would like to have each button for each VC (each annotation - each VC). Is it a good way to show the description of the place in this seperate ViewControllers? I have 25 annotations, so It would be 25 VCs. Here is my code:
import UIKit
import MapKit
class ViewController: UIViewController, MKMapViewDelegate {
let initialLocation = CLLocation(latitude: 85.10786543576327, longitude: 11.03851472106171)
let locationManager = CLLocationManager()
struct Place {
let name: String
let description: String
let type: String
let lattitude: CLLocationDegrees
let longtitude: CLLocationDegrees
var coordinate: CLLocationCoordinate2D {
.init(latitude: lattitude, longitude: longtitude)
}
}
let location = CLLocation()
let places = [Place(name: "One", description: "One", type: "one", lattitude: 81.108187, longtitude: 12.075812),
Place(name: "Two", description: "Two", typ: "two", lattitude: 81.076187, longtitude: 11.000563),
Place(name: "Three", description: "Three", typ: "Three", lattitude: 81.076187, longtitude: 11.000563)]
override func viewDidLoad() {
super.viewDidLoad()
mapView.centerToLocation(initialLocation)
mapView.register(MKMarkerAnnotationView.self, forAnnotationViewWithReuseIdentifier: "identifier")
checkLocationServices()
findPlaces(places)
mapView.delegate = self
}
[...]
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
guard !(annotation is MKUserLocation) else { return nil }
mapView.delegate = self
let annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: String(annotation.hash))
let identifier = "identifier"
annotationView.canShowCallout = true
guard let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier, for: annotation) as? MKMarkerAnnotationView else { return nil }
let rightButton = UIButton(type: .detailDisclosure) // HERE IS THIS BUTTON, BUT I NEED EACH BUTTON FOR EACH ANNOTATION - THIS WAY IT SHOULD BE ONE FOR ALL OF THEM
rightButton.tag = annotation.hash
annotationView.canShowCallout = true
annotationView.rightCalloutAccessoryView = rightButton
[...]
Thank you in advance for your help.
Hello,
I've added two buttons for my annotationView. I have 25 annotations and I would like to have seperate button actions for each annotation. Now I have only one button action for every annotation. Here is my code:
import UIKit
import MapKit
class ViewController: UIViewController, MKMapViewDelegate {
let initialLocation = CLLocation(latitude: 85.10786543576327, longitude: 11.03851472106171)
let locationManager = CLLocationManager()
struct Place {
let name: String
let description: String
let type: String
let lattitude: CLLocationDegrees
let longtitude: CLLocationDegrees
var coordinate: CLLocationCoordinate2D {
.init(latitude: lattitude, longitude: longtitude)
}
}
let location = CLLocation()
let places = [Place(name: "One", description: "One", type: "one", lattitude: 81.108187, longtitude: 12.075812),
Place(name: "Two", description: "Two", typ: "two", lattitude: 81.076187, longtitude: 11.000563),
Place(name: "Three", description: "Three", typ: "Three", lattitude: 81.076187, longtitude: 11.000563)]
[...]
func findPlace(_ miejsca: [Place]) {
for place in places {
let annotations = MKPointAnnotation()
annotations.title = place.name
annotations.subtitle = place.description
annotations.coordinate = CLLocationCoordinate2D(latitude:
place.lattitude, longitude: place.longtitude)
mapView.addAnnotation(annotations)
}
}
@objc func didClickDetailDisclosure(button: UIButton) {
guard let vc = storyboard?.instantiateViewController(withIdentifier: "kopuly_vc") as? KopulyController else {
return
}
present(vc, animated: true)
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
guard !(annotation is MKUserLocation) else { return nil }
mapView.delegate = self
let annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: String(annotation.hash))
let identifier = "identifier"
annotationView.canShowCallout = true
guard let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier, for: annotation) as? MKMarkerAnnotationView else { return nil }
let rightButton = UIButton(type: .detailDisclosure) // HERE IS THIS BUTTON, BUT I NEED EACH BUTTON FOR EACH ANNOTATION - THIS WAY IT SHOULD BE ONE FOR ALL OF THEM
rightButton.tag = annotation.hash
annotationView.canShowCallout = true
annotationView.rightCalloutAccessoryView = rightButton
rightButton.addTarget(self, action: #selector(didClickDetailDisclosure(button:)), for: .touchUpInside)
let leftButton = UIButton(frame: CGRect(
origin: CGPoint.zero,
size: CGSize(width: 25, height: 25)))
leftButton.setBackgroundImage(#imageLiteral(resourceName: "nav"), for: .normal)
annotationView.leftCalloutAccessoryView = leftButton
leftButton.addTarget(self, action: #selector(didClickDetailDisclosure(button:)), for: .touchUpInside)
[...]
Thank you in advance for your help
Hello,
This is the continuation of https://developer.apple.com/forums/thread/692878?login=true&page=1#692455022 where @Calude31 tried to help me. I've added two buttons for my annotationView. I have 25 annotations and I would like to have seperate button actions for each annotation. Now when I try to customize an action per annotation for rightButton switch only changes colors of the annotations NOT the rightButton.addTarget(self, action: #selector(didClickDetailDisclosure(button:)), for: .touchUpInside) - I think because od the return annotationView at the end - I need to change all three annotation parameters (color, icon, button action). Here is my code:
import UIKit
import MapKit
class ViewController: UIViewController, MKMapViewDelegate {
let initialLocation = CLLocation(latitude: 85.10786543576327, longitude: 11.03851472106171)
let locationManager = CLLocationManager()
struct Place {
let name: String
let description: String
let type: String
let lattitude: CLLocationDegrees
let longtitude: CLLocationDegrees
var coordinate: CLLocationCoordinate2D {
.init(latitude: lattitude, longitude: longtitude)
}
}
let location = CLLocation()
let places = [Place(name: "One", description: "One", type: "one", lattitude: 81.108187, longtitude: 12.075812),
Place(name: "Two", description: "Two", typ: "two", lattitude: 81.076187, longtitude: 11.000563),
Place(name: "Three", description: "Three", typ: "Three", lattitude: 81.076187, longtitude: 11.000563)]
[...]
func findPlace(_ miejsca: [Place]) {
for (i, place) in places.enumerated() {
let annotations = MKPointAnnotation()
annotations.title = String(i) + "-" + place.name
annotations.subtitle = place.description
annotations.coordinate = CLLocationCoordinate2D(latitude:
place.lattitude, longitude: place.longtitude)
mapView.addAnnotation(annotations)
}
}
@objc func didClickDetailDisclosure(button: UIButton) {
guard let vc = storyboard?.instantiateViewController(withIdentifier: "kopuly_vc") as? KopulyController else {
return
}
present(vc, animated: true)
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
guard !(annotation is MKUserLocation) else { return nil }
mapView.delegate = self
let annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: String(annotation.hash))
let identifier = "identifier"
annotationView.canShowCallout = true
guard let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier, for: annotation) as? MKMarkerAnnotationView else { return nil }
let rightButton = UIButton(type: .detailDisclosure) // HERE IS THIS BUTTON, BUT I NEED EACH BUTTON FOR EACH ANNOTATION - THIS WAY IT SHOULD BE ONE FOR ALL OF THEM
rightButton.tag = annotation.hash
annotationView.canShowCallout = true
annotationView.rightCalloutAccessoryView = rightButton
rightButton.addTarget(self, action: #selector(didClickDetailDisclosure(button:)), for: .touchUpInside)
let leftButton = UIButton(frame: CGRect(
origin: CGPoint.zero,
size: CGSize(width: 25, height: 25)))
leftButton.setBackgroundImage(#imageLiteral(resourceName: "nav"), for: .normal)
annotationView.leftCalloutAccessoryView = leftButton
leftButton.addTarget(self, action: #selector(didClickDetailDisclosure(button:)), for: .touchUpInside)
switch annotation.title!! {
case "One":
annotationView.markerTintColor = UIColor.gray
annotationView.glyphImage = UIImage(named: "kopula")
case "Two":
annotationView.markerTintColor = UIColor.black
annotationView.glyphImage = UIImage(named: "two")
rightButton.addTarget(self, action: #selector(didClickDetailDisclosure2(button:)), for: .touchUpInside)
case "Three":
annotationView.markerTintColor = UIColor.red
annotationView.glyphImage = UIImage(named: "three")
rightButton.addTarget(self, action: #selector(didClickDetailDisclosure3(button:)), for: .touchUpInside)
default:
annotationView.markerTintColor = UIColor.darkGray
annotationView.glyphImage = UIImage(named: "place")
rightButton.addTarget(self, action: #selector(didClickDetailDisclosure(button:)), for: .touchUpInside)
}
return annotationView
}
}
Hello,
I've implemented a button which locates user on map. I would also to inform user, when location sharing for this app is set to never, that user needs to turn it on in settings. Here are those functions:
func checkLocationServices() {
if CLLocationManager.locationServicesEnabled() {
checkLocationAuthorization()
} else {
// Show alert letting the user know they have to turn this on.
}
}
func checkLocationAuthorization() {
let manager = CLLocationManager()
switch manager.authorizationStatus {
case .authorizedWhenInUse:
mapView.showsUserLocation = true
case .denied: // Show alert telling users how to turn on permissions
break
case .notDetermined:
locationManager.requestWhenInUseAuthorization()
mapView.showsUserLocation = true
case .restricted: // Show an alert letting them know what’s up
break
case .authorizedAlways:
break
@unknown default:
break
}
}
@IBAction func myLocationButtonTapped(_ sender: Any) {
mapView.showsUserLocation = true
mapView.setUserTrackingMode(.follow, animated: true)
}
Hello, Im trying to implement directions (navigation) from my app. All I want to do is to open map app (Google Maps or Apple Maps) with ready to go directions after user click button - in my case leftCalloutAccessoryView called leftButton. I've been trying some options, but without a good result. Here is my code:
func findPlace(_ places: [Place]) {
for place in places {
let annotations = MKPointAnnotation()
annotations.title = place.name
annotations.subtitle = place.description
annotations.coordinate = CLLocationCoordinate2D(latitude:
place.lattitude, longitude: place.longtitude)
mapView.addAnnotation(annotations)
}
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
guard !(annotation is MKUserLocation) else { return nil }
mapView.delegate = self
let annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: String(annotation.hash))
let identifier = "identifier"
annotationView.canShowCallout = true
guard let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier, for: annotation) as? MKMarkerAnnotationView else { return nil }
let rightButton = UIButton(type: .detailDisclosure)
rightButton.tag = annotation.hash
annotationView.canShowCallout = true
annotationView.rightCalloutAccessoryView = rightButton
let leftButton = UIButton(frame: CGRect(
origin: CGPoint.zero,
size: CGSize(width: 25, height: 25)))
leftButton.setBackgroundImage(#imageLiteral(resourceName: "nav"), for: .normal)
annotationView.leftCalloutAccessoryView = leftButton
leftButton.addTarget(self, action: #selector(didClickDetailDisclosureNavigation(button:)), for: .touchUpInside)
@objc func didClickDetailDisclosureNavigation(button: UIButton) {
let launchOptions = [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving]
????.openInMaps(launchOptions: launchOptions)
//Here I've tried some solutions like `annotations.openInMaps(launchOptions: launchOptions)`- but it does not make sense.
}
Hello,
I've implemented directions to my annotations on map. But when Apple Maps are opening I can only see Uknown Location as a destination point. What I would like to do is to have Annotation title instead of Unknown Location. Here is my code:
class AnnotationButton: UIButton {
var annotation: MKPointAnnotation?
}
func findPlace(_ places: [Place]) {
for place in places {
let annotations = MKPointAnnotation()
annotations.title = place.name
annotations.subtitle = place.description
annotations.coordinate = CLLocationCoordinate2D(latitude:
place.lattitude, longitude: place.longtitude)
mapView.addAnnotation(annotations)
}
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
guard !(annotation is MKUserLocation) else { return nil }
let identifier = "identifier"
guard let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier, for: annotation) as? MKMarkerAnnotationView else { return nil }
let leftButton = AnnotationButton(frame: CGRect(
origin: CGPoint.zero,
size: CGSize(width: 25, height: 25)))
leftButton.setBackgroundImage(#imageLiteral(resourceName: "nav"), for: .normal)
annotationView.leftCalloutAccessoryView = leftButton
leftButton.addTarget(self, action: #selector(didClickDetailDisclosureNavigation(button:)), for: .touchUpInside)
if let pointAnnotation = annotation as? MKPointAnnotation {
leftButton.annotation = pointAnnotation
}
@objc func didClickDetailDisclosureNavigation(button: AnnotationButton) {
let launchOptions = [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving]
if let mapItem = button.annotation?.mapItem {
mapItem.openInMaps(launchOptions: launchOptions)
}
}
extension MKPointAnnotation {
var mapItem: MKMapItem {
let placemark = MKPlacemark(coordinate: self.coordinate)
return MKMapItem(placemark: placemark)
}
}