Skip to content

Commit 79df8ca

Browse files
authored
Fix layer order inside aboveLayer compose blocks (#2942)
1 parent f93c473 commit 79df8ca

File tree

10 files changed

+654
-52
lines changed

10 files changed

+654
-52
lines changed

CHANGELOG.md

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

55
# main
6+
## Bug fixes 🐞
7+
* [compose] Fix wrong layer order when using `aboveLayer(..)` composable function.
68

79

810
# 11.10.0-rc.1 January 31, 2025

extension-compose/src/main/java/com/mapbox/maps/extension/compose/annotation/internal/BaseAnnotationNode.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ internal abstract class BaseAnnotationNode(private val mapboxStyleManager: Mapbo
1414
}
1515

1616
@CallSuper
17-
override fun onMoved(parent: MapNode, from: Int, to: Int) {
17+
override fun onMoved(parent: MapNode) {
1818
mapboxStyleManager.repositionCurrentNode(parent)
1919
}
2020

extension-compose/src/main/java/com/mapbox/maps/extension/compose/internal/LayerPositionAwareNode.kt

Lines changed: 50 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.mapbox.maps.extension.compose.internal
22

33
import com.mapbox.maps.LayerPosition
44
import com.mapbox.maps.MapboxStyleManager
5+
import com.mapbox.maps.extension.compose.style.LayerPositionedContent
56
import com.mapbox.maps.extension.compose.style.internal.StyleLayerPositionNode
67
import com.mapbox.maps.logW
78

@@ -18,7 +19,8 @@ internal interface LayerPositionAwareNode {
1819
* Reposition all the layers within the current node according to [getRelativePositionInfo].
1920
*/
2021
fun MapboxStyleManager.repositionCurrentNode(parent: MapNode) {
21-
repositionLayersForCurrentNode(getRelativePositionInfo(parent))
22+
val layerPosition = (parent as? StyleLayerPositionNode)?.layerPosition
23+
repositionLayersForCurrentNode(getRelativePositionInfo(parent, layerPosition))
2224
}
2325

2426
/**
@@ -52,27 +54,61 @@ internal interface LayerPositionAwareNode {
5254

5355
/**
5456
* Search the children of the parent node, and see if there's any other [LayerPositionAwareNode]
55-
* which is on top of the current node, construct the [LayerPosition] with below layer id, so the
57+
* which is rendered on top of this one (for [LayerPositionedContent.belowLayer]) or below (for [LayerPositionedContent.aboveLayer])
58+
* of the current node, construct the [LayerPosition] with the found layer id, so the
5659
* current layer is inserted at the correct position and consistent with the node tree.
5760
*
58-
* If there's nothing above current node, take the [targetLayerPosition] as it's position.
61+
* If there's nothing above/below current node, take the [targetLayerPosition] as its insertion position.
62+
*
63+
* For example, the following compose block:
64+
* ```
65+
* aboveLayer("buildings") {
66+
* layerPositionAwareNode_1
67+
* layerPositionAwareNode_2
68+
* layerPositionAwareNode_3
69+
* }
70+
* ```
71+
* Should be rendered in the map in the following order (top visible layer to bottom layer):
72+
* ```
73+
* layerPositionAwareNode_3
74+
* layerPositionAwareNode_2
75+
* layerPositionAwareNode_1
76+
* "buildings"
77+
* ```
78+
*
79+
* Meaning that the relative position of the layers should be:
80+
* ```
81+
* layerPositionAwareNode_3 above layerPositionAwareNode_2
82+
* layerPositionAwareNode_2 above layerPositionAwareNode_1
83+
* layerPositionAwareNode_1 above "buildings"
84+
* ```
85+
*
5986
*
6087
* @param parent the parent node of the node to be positioned.
6188
* @param targetLayerPosition the optional target layer position, useful in case of [StyleLayerPositionNode].
6289
*/
6390
fun getRelativePositionInfo(
6491
parent: MapNode,
6592
targetLayerPosition: LayerPosition? = null
66-
): LayerPosition? {
67-
return with(parent.children.filterIsInstance<LayerPositionAwareNode>()) {
68-
elementAtOrNull(indexOf(this@LayerPositionAwareNode) + 1)?.getLayerIds()?.firstOrNull()
69-
?.let { belowLayerId ->
70-
LayerPosition(
71-
/* above = */ null,
72-
/* below = */ belowLayerId,
73-
/* at = */ null
74-
)
75-
} ?: targetLayerPosition
93+
): LayerPosition? =
94+
parent.children.filterIsInstance<LayerPositionAwareNode>().let { children ->
95+
val me = this@LayerPositionAwareNode
96+
val isAbove = targetLayerPosition?.above != null
97+
val anchorLayerIdx = children.indexOf(me) + if (isAbove) {
98+
-1
99+
} else {
100+
1
101+
}
102+
val anchorLayerNode = children.elementAtOrNull(anchorLayerIdx)
103+
return if (anchorLayerNode == null) {
104+
targetLayerPosition
105+
} else {
106+
val anchorLayerId = anchorLayerNode.getLayerIds().first()
107+
LayerPosition(
108+
/* above = */ if (isAbove) anchorLayerId else null,
109+
/* below = */ if (isAbove) null else anchorLayerId,
110+
/* at = */ null
111+
)
112+
}
76113
}
77-
}
78114
}

extension-compose/src/main/java/com/mapbox/maps/extension/compose/internal/MapApplier.kt

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.mapbox.maps.extension.compose.internal
22

33
import androidx.compose.runtime.AbstractApplier
4+
import com.mapbox.common.LogConfiguration
5+
import com.mapbox.common.LoggingLevel
46
import com.mapbox.maps.MapView
57
import com.mapbox.maps.logD
68

@@ -12,20 +14,17 @@ internal abstract class MapNode {
1214
val children = mutableListOf<MapNode>()
1315

1416
/**
15-
* Invoked when the [MapNode] is attached to the node tree.
17+
* Invoked when this [MapNode] is attached to the node tree.
1618
*/
1719
open fun onAttached(parent: MapNode) {}
1820

1921
/**
20-
* Invoked when the [MapNode] is moved inside the node tree.
21-
*
22-
* @param from original position
23-
* @param to the target position
22+
* Invoked when this [MapNode] is moved inside the node tree.
2423
*/
25-
open fun onMoved(parent: MapNode, from: Int, to: Int) {}
24+
open fun onMoved(parent: MapNode) {}
2625

2726
/**
28-
* Invoked when the [MapNode] is removed from the node tree.
27+
* Invoked when this [MapNode] is removed from the node tree.
2928
*/
3029
open fun onRemoved(parent: MapNode) {}
3130

@@ -90,12 +89,10 @@ internal class MapApplier(
9089
override fun move(from: Int, to: Int, count: Int) {
9190
logD(TAG, "move: $from, $to, $count")
9291
current.children.move(from, to, count)
93-
repeat(count) { offset ->
94-
current.children[to + offset - if (to > from) count else 0].onMoved(
95-
parent = current,
96-
from = from + offset,
97-
to = to + offset - if (to > from) count else 0
98-
)
92+
93+
// Let's move the children nodes in the tree
94+
current.children.forEach { child ->
95+
child.onMoved(current)
9996
}
10097
printNodesTree("MapNodeMoved")
10198
}
@@ -110,7 +107,13 @@ internal class MapApplier(
110107
}
111108

112109
private fun printNodesTree(tag: String = TAG) {
113-
walkChildren(tag = tag, node = root)
110+
// We don't know how many nodes are in the tree, so we only walk the tree when the logging
111+
// level is DEBUG.
112+
LogConfiguration.getLoggingLevel(tag)?.let {
113+
if (it.ordinal <= LoggingLevel.DEBUG.ordinal) {
114+
walkChildren(tag = tag, node = root)
115+
}
116+
}
114117
}
115118

116119
private fun walkChildren(tag: String = TAG, prefix: String = "\t", node: MapNode) {

extension-compose/src/main/java/com/mapbox/maps/extension/compose/style/layers/internal/LayerNode.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,8 @@ internal class LayerNode(
7777
}
7878
}
7979

80-
override fun onMoved(parent: MapNode, from: Int, to: Int) {
81-
logD(TAG, "onMoved: from $from to $to")
80+
override fun onMoved(parent: MapNode) {
81+
logD(TAG, "onMoved")
8282
dispatchWhenStyleDataLoaded {
8383
it.repositionCurrentNode(parent)
8484
}

0 commit comments

Comments
 (0)