问题
How can I simply detect zoom level changes? Is it possible?
I simply need to hide my annotation views when zoom level is not enough.
regionDidChange:animated: is not intended to use for me. Any other way?
I need to hide my labels here:
and show them here:
This is what I currently do with my labels:
class CardAnnotation: MGLPointAnnotation {
var card: Card
init(card: Card) {
self.card = card
super.init()
let coordinates = card.border.map { $0.coordinate }
let sumLatitudes = coordinates.map { $0.latitude }.reduce(0, +)
let sumLongitudes = coordinates.map { $0.longitude }.reduce(0, +)
let averageLatitude = sumLatitudes / Double(coordinates.count)
let averageLongitude = sumLongitudes / Double(coordinates.count)
coordinate = CLLocationCoordinate2D(latitude: averageLatitude, longitude: averageLongitude)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
var annotations = [CardAnnotation]()
mapView.addAnnotations(annotations)
回答1:
Of the two main ways to add overlays to an MGLMapView, the runtime styling API is better suited for text labels and also for varying the appearance based on the zoom level. While you’re at it, you might as well create the polygons using the same API too.
Start by creating polygon features for the areas you want shaded in:
var cards: [MGLPolygonFeature] = []
var coordinates: [CLLocationCoordinate2D] = […]
let card = MGLPolygonFeature(coordinates: &coordinates, count: UInt(coordinates.count))
card.attributes = ["address": 123]
// …
cards.append(card)
Within any method that runs after the map finishes loading, such as MGLMapViewDelegate.mapView(_:didFinishLoading:), add a shape source containing these features to the current style:
let cardSource = MGLShapeSource(identifier: "cards", features: cards, options: [:])
mapView.style?.addSource(cardSource)
With the shape source in place, create a style layer that renders the polygon features as mauve fills:
let fillLayer = MGLFillStyleLayer(identifier: "card-fills", source: cardSource)
fillLayer.fillColor = NSExpression(forConstantValue: #colorLiteral(red: 0.9098039216, green: 0.8235294118, blue: 0.9647058824, alpha: 1))
mapView.style?.addLayer(fillLayer)
Then create another style layer that renders labels at each polygon feature’s centroid. (MGLSymbolStyleLayer automatically calculates the centroids, accounting for irregularly shaped polygons.)
// Same source as the fillLayer.
let labelLayer = MGLSymbolStyleLayer(identifier: "card-labels", source: cardSource)
// Each feature’s address is an integer, but text has to be a string.
labelLayer.text = NSExpression(format: "CAST(address, 'NSString')")
// Smoothly interpolate from transparent at z16 to opaque at z17.
labelLayer.textOpacity = NSExpression(format: "mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)",
[16: 0, 17: 1])
mapView.style?.addLayer(labelLayer)
As you customize these style layers, pay particular attention to the options on MGLSymbolStyleLayer that control whether nearby symbols are automatically hidden due to collision. You may find that the automatic collision detection makes it unnecessary to specify the textOpacity property.
When you create the source, one of the options you can pass into the MGLShapeSource initializer is MGLShapeSourceOption.clustered. However, in order to use that option, you’d have to create MGLPointFeatures, not MGLPolygonFeatures. Fortunately, MGLPolygonFeature has a coordinate property that lets you find the centroid without manual calculations:
var cardCentroids: [MGLPointFeature] = []
var coordinates: [CLLocationCoordinate2D] = […]
let card = MGLPolygonFeature(coordinates: &coordinates, count: UInt(coordinates.count))
let cardCentroid = MGLPointFeature()
cardCentroid.coordinate = card.coordinate
cardCentroid.attributes = ["address": 123]
cardCentroids.append(cardCentroid)
// …
let cardCentroidSource = MGLShapeSource(identifier: "card-centroids", features: cardCentroids, options: [.clustered: true])
mapView.style?.addSource(cardCentroidSource)
This clustered source can only be used with MGLSymbolStyleLayer or MGLCircleStyleLayer, not MGLFillStyleLayer. This example shows how to work with clustered points in more detail.
回答2:
One option is to add the labels as a MGLSymbolStyleLayer, then determine the textOpacity based on zoom level.
If you are using the current version of the Maps SDK for iOS, you could try something like:
symbols.textOpacity = NSExpression(format: "mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", [16.9: 0, 17: 1])
The dynamically styled interactive points example shows one approach to this.
回答3:
Is the problem that when you zoom out, your annotations are too close together? If so, it is better to group them together than to hide them entirely. See Decluttering a Map with MapKit Annotation Clustering.
来源:https://stackoverflow.com/questions/50471924/mapbox-detect-zoomlevel-changes