Skip to content

Commit 2d43e11

Browse files
evil159github-actions[bot]
authored andcommitted
[maps-ios] Fix ornaments positioning (#10738)
We have reports of ornaments being positioned incorrectly when upgrading to 11.18. For indoor the positioning of ornaments changed to stacking(one above/below another if in the same corner), which turns out to be not working with our way of hiding ornament views(isHidden = true, which does't remove views from layout participation so there are extra gaps if there is a hidden view on the edge/middle). We could either: * fix gaps issue e.g. by placing them in a stack view(which removes subviews from layout when hidden) * revert to previous non-stacking positioning In this PR I have chosen to revert to the previous positioning, as for some customers this will be a behavior breaking change. This change was done for indoor selector view, so it stacks nicely below any ornament it was positioned under. I suggest we address this the same way as other ornaments - by adjusting offset, in this PR I the offset of indoor selector to line up nicely under the compass, if the user changes the position of the selector then it is on them to adjust margins for proper alignment(same as with the rest of the ornaments). Addresses https://mapbox.atlassian.net/browse/MAPSIOS-2122 mapbox/mapbox-maps-flutter#1110 cc @mapbox/maps-ios cc @mapbox/sdk-platform GitOrigin-RevId: 1d3e93076afbf04dcfeb3ebcd6be62ec7baa0071
1 parent f314ee6 commit 2d43e11

File tree

3 files changed

+35
-39
lines changed

3 files changed

+35
-39
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ Mapbox welcomes participation and contributions from everyone.
44

55
## main
66

7+
* Fix incorrect positioning of map ornaments when multiple ornaments are placed in the same corner.
8+
79
## 11.19.0 - 24 February, 2026
810

911
### Features ✨ and improvements 🏁

Sources/Examples/All Examples/Lab/IndoorExample.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ final class IndoorExample: UIViewController, ExampleProtocol {
2121

2222
mapView.ornaments.options.scaleBar.visibility = .visible
2323
mapView.ornaments.options.indoorSelector.visibility = .visible
24+
mapView.ornaments.options.indoorSelector.margins = CGPoint(x: 8.0, y: 56.0)
2425

2526
var puckConfiguration = Puck2DConfiguration.makeDefault(showBearing: true)
2627
puckConfiguration.pulsing = nil

Sources/MapboxMaps/Ornaments/OrnamentsManager.swift

Lines changed: 32 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ public final class OrnamentsManager {
124124
private let _indoorSelectorView: IndoorSelectorView
125125

126126
private var constraints = [NSLayoutConstraint]()
127-
private var viewsByPosition: [OrnamentPosition: [UIView]] = [:] // Allow to stack views at the same position
128127
private var cancellables = Set<AnyCancelable>()
129128

130129
init(options: OrnamentOptions,
@@ -207,7 +206,6 @@ public final class OrnamentsManager {
207206
// Remove previously-added constraints
208207
NSLayoutConstraint.deactivate(constraints)
209208
constraints.removeAll()
210-
viewsByPosition.removeAll()
211209

212210
// Update the position for the ornaments
213211
let logoViewConstraints = constraints(with: _logoView,
@@ -274,44 +272,39 @@ public final class OrnamentsManager {
274272
guard let layoutGuide = view.superview?.safeAreaLayoutGuide else {
275273
return []
276274
}
277-
278-
let stackSpacing: CGFloat = 8.0
279-
var viewsAtPosition = viewsByPosition[position] ?? []
280-
let previousView = viewsAtPosition.last
281-
viewsAtPosition.append(view)
282-
viewsByPosition[position] = viewsAtPosition
283-
284-
var result: [NSLayoutConstraint] = []
285-
286275
switch position {
287-
case .topLeft, .bottomLeft:
288-
result.append(view.leftAnchor.constraint(equalTo: layoutGuide.leftAnchor, constant: margins.x))
289-
case .topRight, .bottomRight:
290-
result.append(view.rightAnchor.constraint(equalTo: layoutGuide.rightAnchor, constant: -margins.x))
291-
case .topLeading, .bottomLeading:
292-
result.append(view.leadingAnchor.constraint(equalTo: layoutGuide.leadingAnchor, constant: margins.x))
293-
case .topTrailing, .bottomTrailing:
294-
result.append(view.trailingAnchor.constraint(equalTo: layoutGuide.trailingAnchor, constant: -margins.x))
276+
case .topLeft:
277+
return [
278+
view.leftAnchor.constraint(equalTo: layoutGuide.leftAnchor, constant: margins.x),
279+
view.topAnchor.constraint(equalTo: layoutGuide.topAnchor, constant: margins.y)]
280+
case .topRight:
281+
return [
282+
view.rightAnchor.constraint(equalTo: layoutGuide.rightAnchor, constant: -margins.x),
283+
view.topAnchor.constraint(equalTo: layoutGuide.topAnchor, constant: margins.y)]
284+
case .bottomLeft:
285+
return [
286+
view.leftAnchor.constraint(equalTo: layoutGuide.leftAnchor, constant: margins.x),
287+
view.bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor, constant: -margins.y)]
288+
case .bottomRight:
289+
return [
290+
view.rightAnchor.constraint(equalTo: layoutGuide.rightAnchor, constant: -margins.x),
291+
view.bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor, constant: -margins.y)]
292+
case .topLeading:
293+
return [
294+
view.leadingAnchor.constraint(equalTo: layoutGuide.leadingAnchor, constant: margins.x),
295+
view.topAnchor.constraint(equalTo: layoutGuide.topAnchor, constant: margins.y)]
296+
case .topTrailing:
297+
return [
298+
view.trailingAnchor.constraint(equalTo: layoutGuide.trailingAnchor, constant: -margins.x),
299+
view.topAnchor.constraint(equalTo: layoutGuide.topAnchor, constant: margins.y)]
300+
case .bottomLeading:
301+
return [
302+
view.leadingAnchor.constraint(equalTo: layoutGuide.leadingAnchor, constant: margins.x),
303+
view.bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor, constant: -margins.y)]
304+
case .bottomTrailing:
305+
return [
306+
view.trailingAnchor.constraint(equalTo: layoutGuide.trailingAnchor, constant: -margins.x),
307+
view.bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor, constant: -margins.y)]
295308
}
296-
297-
let isTopPosition = [.topLeft, .topRight, .topLeading, .topTrailing].contains(position)
298-
let isBottomPosition = [.bottomLeft, .bottomRight, .bottomLeading, .bottomTrailing].contains(position)
299-
300-
if let previousView = previousView {
301-
if isTopPosition {
302-
result.append(view.topAnchor.constraint(equalTo: previousView.bottomAnchor, constant: stackSpacing))
303-
} else if isBottomPosition {
304-
result.append(view.bottomAnchor.constraint(equalTo: previousView.topAnchor, constant: -stackSpacing))
305-
}
306-
} else {
307-
// First view at this position - anchor to safe area
308-
if isTopPosition {
309-
result.append(view.topAnchor.constraint(equalTo: layoutGuide.topAnchor, constant: margins.y))
310-
} else if isBottomPosition {
311-
result.append(view.bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor, constant: -margins.y))
312-
}
313-
}
314-
315-
return result
316309
}
317310
}

0 commit comments

Comments
 (0)