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
How to Set Exit Code Value for a Command Line Utility in Swift
What Makes a Property a Computed Property in Swift
Toggle Selection in a List - Swiftui
How to Make a Button Have a Rounded Border in Swift
How to Get Indexpath.Row in Cell.Swift
How to Destroy a Singleton in Swift
How to Get Iobluetoothdevice's Battery Level, Using Swift and Appkit (Xcode for MACos)
Swift Sort Dictionary by Value
How to Call the More Specific Method of Overloading
Swiftui: How to Make Entire Shape Recognize Gestures When Stroked
Pattern Match and Conditionally Bind in a Single Switch Statement
Uibarbuttonitem Doesn't Work When Created as a Property, But Does When Created in a Function