How to Implement iOS 11's Mkusertrackingbutton

MKUserTrackingBarButtonItem functionality, but not in a stupid bar button

Unfortunately, iOS doesn't expose an isolated version of MKUserTrackingBarButtonItem. (You might want to file a radar to request this. Feel free to dupe mine.)

I suggest embedding MKUserTrackingBarButtonItem in a UIToolbar with a clear background.

Add MKUserTrackingBarButtonItem to UIView

So it seems there is no way to directly add any kind of bar button item to a UIView. We're going to have to subclass UIToolbar to make a totally invisible toolbar. Override - (void)drawRect:(CGRect)rect and put nothing, not even a [super drawRect]. Then, in init, run the following code:

self = [super init];
self.backgroundColor = [UIColor clearColor];
self.opaque = NO;
self.translucent = YES;

return self;

For more details, visit this link: Couldn't UIToolBar be transparent?

Xamarin Forms IOS - MKUserTrackingButton position

If you want to use Frame to change a Control's position. You should delete button.TranslatesAutoresizingMaskIntoConstraints = false;. This code will disable the Frame, and use autoLayout to place your controls.

Also you can try to use autoLayout:

button.TopAnchor.ConstraintEqualTo(Map.TopAnchor, 100).Active = true;
button.LeadingAnchor.ConstraintEqualTo(Map.LeadingAnchor, 100).Active = true;
button.WidthAnchor.ConstraintEqualTo(52).Active = true;
button.HeightAnchor.ConstraintEqualTo(44).Active = true;

How to set Mapkit user tracking button state

The user tracking mode must be set after the map view has fully loaded. In viewDidLoad this is not the case.

You can use the MKMapViewDelegate method mapViewDidFinishLoading(mapView:) to know when the map has loaded:

class MyMapViewController: UIViewController, MKMapViewDelegate {

// ...

override func viewDidLoad() {
super.viewDidLoad()

// ...
mapView.delegate = self
}

// ...

func mapViewDidFinishLoadingMap(_ mapView: MKMapView) {
mapView.setUserTrackingMode(.followWithHeading, animated: true)
}

// ...

}

Adding cluster annotations to a map view, which has several custom annotation views

Try to register your Annotations with String reuse Identifier:

mapView.register(AnnotationViewMarker.self, forAnnotationViewWithReuseIdentifier: "marker")
mapView.register(AppleClusterAnnotationView.self, forAnnotationViewWithReuseIdentifier: "cluster")

I already had this problem too.
In case here is an example that work in my app:

override func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {        
if annotation is MKUserLocation || annotation is UserAnnotation {
return nil
}

if let marker = annotation as? WifiAnnotation {
var view = mapView.dequeueReusableAnnotationView(withIdentifier: "marker") as? AnnotationViewMarker
if view == nil {
view = AnnotationViewMarker(annotation: marker, reuseIdentifier: "marker")
}
return view

} else if let cluster = annotation as? MKClusterAnnotation {
var view = mapView.dequeueReusableAnnotationView(withIdentifier: "cluster") as? AppleClusterAnnotationView
if view == nil {
view = AppleClusterAnnotationView(annotation: cluster, reuseIdentifier: "cluster")
}
return view

}

return nil
}

here an exemple of my MKAnnotationView Class:

class AppleClusterAnnotationView: MKAnnotationView {
override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
displayPriority = .defaultLow
//collisionMode = .circle
centerOffset = CGPoint(x: 0, y: -10) // Offset center point to animate better with marker annotations
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

override var annotation: MKAnnotation? {
willSet {
if let cluster = newValue as? MKClusterAnnotation {
let renderer = UIGraphicsImageRenderer(size: CGSize(width: 40, height: 40))
let count = cluster.memberAnnotations.count
let uniCount = cluster.memberAnnotations.filter { member -> Bool in
return (member as! WifiAnnotation).wifiType != "Ad"
}.count
image = renderer.image { _ in
// Fill full circle with tricycle color
UIColor(red: 52/255, green: 131/255, blue: 223/255, alpha: 0.22).setFill()
UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: 40, height: 40)).fill()

// Fill pie with unicycle color
UIColor(red: 52/255, green: 131/255, blue: 223/255, alpha: 0.22).setFill()
let piePath = UIBezierPath()
piePath.addArc(withCenter: CGPoint(x: 20, y: 20), radius: 20,
startAngle: 0, endAngle: (CGFloat.pi * 2.0 * CGFloat(uniCount)) / CGFloat(count),
clockwise: true)
piePath.addLine(to: CGPoint(x: 20, y: 20))
piePath.close()
piePath.fill()

// Fill inner circle with white color
UIColor.white.setFill()
UIBezierPath(ovalIn: CGRect(x: 8, y: 8, width: 24, height: 24)).fill()

// Finally draw count text vertically and horizontally centered
let attributes = [ NSAttributedStringKey.foregroundColor: UIColor.black,
NSAttributedStringKey.font: UIFont.boldSystemFont(ofSize: 15)]
let text = "\(count)"
let size = text.size(withAttributes: attributes)
let rect = CGRect(x: 20 - size.width / 2, y: 20 - size.height / 2, width: size.width, height: size.height)
text.draw(in: rect, withAttributes: attributes)

}
}
}
}}

And finally my MKMarkerAnnotationView.
With that you are all setup to make it works. You only have to setup your MKAnnotation.

MKMarkerAnnotationView:

class AnnotationViewMarker: MKMarkerAnnotationView {

override open var annotation: MKAnnotation? {
willSet {
if let annotation = newValue as? WifiAnnotation {
clusteringIdentifier = "WifiAnnotation"

if annotation.wifiType == "yyy" {
glyphImage = UIImage(named: "yyy")
selectedGlyphImage = UIImage(named: "yyy")
markerTintColor = UIColor("#303030")
glyphTintColor = .white
displayPriority = .defaultHigh
titleVisibility = .visible
animatesWhenAdded = true


} else {
glyphImage = UIImage(named: "xxx")
selectedGlyphImage = UIImage(named: "xxx")
markerTintColor = UIColor("#3483DF")
glyphTintColor = .white
displayPriority = .required
titleVisibility = .visible
animatesWhenAdded = true

let accessButton = UIButton(frame: CGRect(x: 0, y: 0, width: 20, height: 20))
accessButton.setImage(self.accessAnnotation, for: .normal) //UIImage(named: "accessAnnotation"), for: .normal)
rightCalloutAccessoryView = accessButton
}

//collisionMode = .circle
}

}
}

}



Related Topics



Leave a reply



Submit