I have a problem, I have to constantly reload my view as I have to be able to view within this function the value of a UISlider that is constantly updated through an animation made through a function that manages the touch of a button. I noticed that when I open the map this slider value always remains fixed at the initial value, despite the latter having changed. How do I update the annotations? I have read on other posts about deleting and re-adding them:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?
{
if (annotation is MapEarthquakeAnnotation) {
let mapEqAnnotation = annotation as! MapEarthquakeAnnotation
var view: MKPinAnnotationView
print("MARIOCASH",Int(sliderTime.value))
if let dequeuedView = mapView.dequeueReusableAnnotationView(withIdentifier: mapEqAnnotation.identifier) as? MKPinAnnotationView
{
// Recycle old view
dequeuedView.annotation = annotation
view = dequeuedView
}
else
{
// Create new view
view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: mapEqAnnotation.identifier)
view.canShowCallout = true
view.pinTintColor = UIColor.brown
let infoButton = UIButton(type: .infoDark)
infoButton.addTarget(self, action: #selector(infoButtonClicked(_:)), for: .touchUpInside)
view.rightCalloutAccessoryView = infoButton
}
return view
}else if annotation is MapSeismometerAnnotation
{
if let annotation = annotation as? MapSeismometerAnnotation
{
var view: MKPinAnnotationView
/*
// Recycle old view
if let dequeuedView = mapView.dequeueReusableAnnotationView(withIdentifier: annotation.identifier) as? MKPinAnnotationView
{
dequeuedView.annotation = annotation
view = dequeuedView
}
else
{ */
// Create new view
view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: annotation.identifier)
view.canShowCallout = true
view.pinTintColor = UIColor.green
view.image = UIImage(named: "pin-verde")
if annotation.identifier == "redpin"
{
var count = 0
var c = 0.8 //valore iniziale dell'aplha per l'opacità del pin rosso
view.image = UIImage(named: "pin-rosso")
Timer.scheduledTimer(withTimeInterval: 1,repeats: true)
{t in //ogni secondo questo timer cambia il valore dell'alpha del pin che sta vibrando
view.alpha = CGFloat(c)
count += 1
c -= 0.15
if count == 5
{
t.invalidate()
}
}
}
return view
//}
}
return nil
}
return nil
}
Related
I could not found any document, video or stackoverflow answer.
Here is my problem. I created map and add into my custom MKAnnotation and MKAnnotationView.
I want to let user to create custom pin and save to it's local via CoreData
MyCustomAnnotation has same attributes which is title, subtitle, and coordinate.
The first solution that I come up with put a button which creates a draggable pin to user location.
But I need to get less complex, more sophistication solution.
private func addPins() {
let list = PrivateLocations.shared.initLocations()
for pin in list {
map.addAnnotation(pin)
}
}
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
if view.annotation is MKUserLocation { return }
let views = Bundle.main.loadNibNamed("CustomCalloutView", owner: nil, options: nil)
let customView = views?[0] as! CustomCalloutView
customView.delegate = self
customView.isUserInteractionEnabled = true
customView.titleLabel.text = view.annotation?.title!
customView.desc.text = view.annotation?.subtitle!
customView.center = CGPoint(x: view.bounds.size.width / 2, y: -customView.bounds.size.height*0.52)
view.addSubview(customView)
map.setCenter((view.annotation?.coordinate)!, animated: true)
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
} else {
let annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: "CustomAnnotationView")
annotationView.image = UIImage(named: "myImage")
annotationView.canShowCallout = false
return annotationView
}
}
And finally here is my CustomPin class :
var coordinate: CLLocationCoordinate2D
var title: String?
var subtitle: String?
init(_ title: String, _ subtitle: String, _ coordinate: CLLocationCoordinate2D) {
self.title = title
self.subtitle = subtitle
self.coordinate = coordinate
}
That's how I solve this problem,
1) Create a UIView for user show where he wants to add an annotation.
2) Add a pan gesture recognizer in it.
func addPanGesture(view: UIView) {
let pan = UIPanGestureRecognizer(target: self, action: #selector (self.handlePan(sender:)))
view.addGestureRecognizer(pan)
}
3) In my selector func, I call pinDropped() func
#objc func handlePan(sender: UIPanGestureRecognizer) {
let view = sender.view!
let translation = sender.translation(in: self.mapView)
switch sender.state {
case .began, .changed:
pinImage.center = CGPoint(x: dropPinImage.center.x + translation.x, y: dropPinImage.center.y + translation.y)
sender.setTranslation(CGPoint.zero, in: view)
break
default:
pinDropped()
break
}
}
4) I write what will be happening in my pinDropped func
func pinDropped() {
DispatchQueue.main.async {
let pin = CustomPin(self.lastOrigin, "pin")
self.mapView.addAnnotation(pin)
}
self.saveButton.alpha = 1
pinImage.alpha = 0
}
I have a class MapItem which implements MKAnnotation protocol. I am using MKMarkerAnnotationView for displaying Annotations on map.
According to Documentation,
glyphText property of MKMarkerAnnotationView when set to nil, it produces pin image on the marker.
When Clustering the annotation, I want the same pin image on the marker. But system by default sets this to the number of annotations clustered within this cluster.
I even tried setting this property to nil, but has no effect.
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if let item = annotation as? MapItem {
let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: "mapItem") as? MKMarkerAnnotationView
?? MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: "mapItem")
annotationView.annotation = item
annotationView.glyphText = nil
annotationView.clusteringIdentifier = "mapItemClustered"
return annotationView
} else if let cluster = annotation as? MKClusterAnnotation {
let clusterView = mapView.dequeueReusableAnnotationView(withIdentifier: "clusterView") as? MKMarkerAnnotationView
?? MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: "clusterView")
clusterView.annotation = cluster
clusterView.glyphText = nil
return clusterView
} else {
return nil
}
}
This is how I do it:
class POIMarkerClusterView: MKMarkerAnnotationView {
override var annotation: MKAnnotation? {
willSet {
update(newValue: newValue)
}
}
private func update(newValue: MKAnnotation?) {
if let cluster = newValue as? MKClusterAnnotation {
self.image = POIClusterImage(poiStatistics: poiStatistics, count: count)
// MKMarkerAnnotationView's default rendering usually hides our own image.
// so we make it invisible:
self.glyphText = ""
self.glyphTintColor = UIColor.clear
self.markerTintColor = UIColor.clear
}
}
}
This means you can set an arbitrary image that is rendered as the annotation view. I create the image dynamically, but you can just borrow the image from the MKMarkerAnnotationView and set it here, so it looks like the pin that you want.
The main trick is to use UIColor.clear to hide what you don't want to see.
So, I have a swift application (swift 3) who use a map, in this map I have many annotation who gets up to date when user change region of map.
I wanted to use the pod "Cluster", I add it and when I zoom in to show what was in the cluster, the annotations appear several times almost at the same place (some time it form a circle, see picture)
I have already tried to filter my list to get only once instance of annotation in cluster but it doesn't works.
This method is call each time the user change region :
func createAnnotations(pois list:[PlaceModel]) {
poiAnnotations.removeAll()
let filteredAnnotations = mapView.annotations.filter { annotation in
//if annotation is MKUserLocation { return false } // don't remove MKUserLocation
if let temp = annotation.subtitle, let value = temp {
return value == "Place"
}
return false
}
clusterManager.remove(poiAnnotations)
clusterManager.remove(filteredAnnotations)
for poi in list {
let centerLocation = CLLocation(latitude: mapView.centerCoordinate.latitude, longitude: mapView.centerCoordinate.longitude)
if poi.getLocation().distance(from: centerLocation) > Double(Constants.POI_Radius) {
continue
}
let annotation = Annotation()
annotation.coordinate = CLLocationCoordinate2D(latitude: poi.latitude!, longitude: poi.longitude!)
annotation.title = poi.name!
annotation.subtitle = "Place"
annotation.type = .image( Images.MapPins.velhop)
// For first value
if poiAnnotations.isEmpty {
poiAnnotations.append(annotation)
}
for pois in poiAnnotations {
if poiAnnotations.contains(where: {$0.title == poi.name}) {
// Do nothing
} else {
poiAnnotations.append(annotation)
}
}
}
clusterManager.add(poiAnnotations)
}
And Here the place where the clusters and the annotations are created :
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if let annotation = annotation as? ClusterAnnotation {
let identifier = "Cluster"
var view = mapView.dequeueReusableAnnotationView(withIdentifier: identifier)
// Type for cluster
let color = UIColor(red: 255/255, green: 149/255, blue: 0/255, alpha: 1)
let type:ClusterAnnotationType = .color(color, radius: 25)
if let view = view as? BorderedClusterAnnotationView {
view.annotation = annotation
view.configure(with: type)
} else {
view = BorderedClusterAnnotationView(annotation: annotation, reuseIdentifier: identifier, type: type, borderColor: .white)
}
return view
} else {
let identifier = "Pin"
var view = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKPinAnnotationView
if let view = view {
view.annotation = annotation
} else {
view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
}
return view
}
}
I tried several things that did not succeed..
Thanks in advance.
I have a custom annotationView on my map, when I select the custom annotation i want to create a action and pass the annotation data to another view. The best way for it to work I would have to use the built in func didSelect. When i do select the custom annotation nothing thing happen. Im not show why the didSelect function did not get called thank you in advance.
class RquestCustomPointAnnotation:MKPointAnnotation {
var image: String!
}
func placeRquestByUsersOnMap(){
//retrieve item from firebase
var markerArray = [MKPointAnnotation]()
let path = "rquest/frontEnd/posts/userCreatedPost"
self.childRef(path).observe(.childAdded, andPreviousSiblingKeyWith: {snapshot, _ in
//get status
if let status = snapshot.childSnapshot(forPath: "status").value as? String {
if status == "pending"{
let indentifier = "rquest"
if let coordinate = snapshot.childSnapshot(forPath: "coordinate").value as? NSDictionary {
let lat = coordinate["lat"] as! Double
let long = coordinate["long"] as! Double
let location = CLLocationCoordinate2D(latitude: lat, longitude: long)
let point = RquestCustomPointAnnotation()
let rquestView = MKAnnotationView(annotation: point, reuseIdentifier: indentifier)
point.image = "22"
let key = snapshot.key
point.coordinate = location
point.accessibilityValue = key
point.accessibilityLabel = "Rquest"
markerArray.append(point)
self.mapView.addAnnotation(rquestView.annotation!)
//create an obserarver to check if it is
let paths = "rquest/frontEnd/posts/userCreatedPost/\(key)/"
self.childRef(paths).observe(.childChanged, andPreviousSiblingKeyWith: { (snap, _) in
if snap.key == "status" {
if let status = snap.value as? String {
if status != "pending" {
for i in markerArray {
if i.accessibilityValue == key {
self.mapView.removeAnnotation(i)
}
}
}
}
}
})
}
}
}
})
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is RquestCustomPointAnnotation {
let reuseIdentifier = "rquest"
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseIdentifier)
if annotationView == nil {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseIdentifier)
annotationView?.canShowCallout = true
} else {
annotationView?.annotation = annotation
}
let customPointAnnotation = annotation as! RquestCustomPointAnnotation
annotationView?.image = UIImage(named: customPointAnnotation.image)
return annotationView
}
}
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
print("did select")
}
You have canShowCallout set to true. So, when you tap on it, do you want callout or have it call didSelect? (Usually you'd do one or the other, but not both.) And are you seeing your callout?
I notice a curious behavior that if (a) the annotation doesn't have a title, and (b) the annotation view's canShowCallout is true, then not only can it not show the callout, but it also prevents the didSelect from being called.
You may either want to turn canShowCallout to false, or make sure your annotation has a title.
I'm using the cocoapod FBAnnotationClusteringSwift and it's possible to group my annotations together. However I want to loop over all those annotations that are clustered together when the cluster annotation is tapped.
How do I do this?
func mapView(mapView: MKMapView, didSelectAnnotationView view: MKAnnotationView) {
if (view.annotation!.isKindOfClass(FBAnnotationCluster) == true){
//I WANT TO LOOP OVER ALL ANNOTATIONS IN THE CLUSTER HERE
}
if (view.annotation!.isKindOfClass(ItemAnnotation) == true){
let annotation = view.annotation! as? ItemAnnotation
if let annotation = annotation, let item = annotation.item, d = delegate{
d.itemAnnotationPressed(item)
}
}
}
func mapView(mapView: MKMapView, didSelectAnnotationView view: MKAnnotationView) {
if (view.annotation!.isKindOfClass(FBAnnotationCluster) == true){
let annotation = view.annotation! as? FBAnnotationCluster
var itemListFromAnnotation = [Item]()
for annotation in (annotation?.annotations)! {
let itemAnnotation = annotation as? ItemAnnotation
itemListFromAnnotation.append((itemAnnotation?.item)!)
}
if let d = delegate{
d.itemClusterAnnotationPressed(itemListFromAnnotation)
}
}
if (view.annotation!.isKindOfClass(ItemAnnotation) == true){
mapView.deselectAnnotation(view.annotation, animated: false)
let annotation = view.annotation! as? ItemAnnotation
if let annotation = annotation, let item = annotation.item, d = delegate{
d.itemAnnotationPressed(item)
}
}
}