Status Update
Comments
an...@google.com <an...@google.com>
za...@gmail.com <za...@gmail.com> #2
I've got a fix for this, will try to post a CL as soon as I remember how to use repo
😅
In the findBounds
function on
a == b ->
// case 2
listOf(offset)
should be
a == b ->
// case 2
listOf(a /* or b */)
because the filter
at the top of the findBounds
accounts for rounding, which means that it's possible for this code to consider offset == a == b
when really offset
is not equal to either. That breaks when SwipeableState
tries to use the returned bounds value as a key into the anchor map
I've verified that this fixes the problem by copying the swipeable code and applying the fix.
ap...@google.com <ap...@google.com> #4
Branch: androidx-main
commit 32d335ae09b704ce6e52b3e80d28a1cc8cdae474
Author: Zach Klippenstein <zach.klippenstein@gmail.com>
Date: Sun Aug 01 17:14:29 2021
Fix swipeable exception when offset is very close to an anchor.
Bug: 191993377
The logic in the findBounds function that determines when the given offset is an exact match for an anchor accounts for rounding error when comparing the floats. This means that, even when an offset is considered an exact match, the actual offset value might not be exactly equal to the matching anchor value. This breaks the logic in SwipeableState's progress getter, which uses the value returned by findBounds as a key into the anchors map. If that returned value is not exactly equal, the map throws a NoSuchElementException.
This fixes the issue by making findBounds return the anchor that was considered an exact match instead of the offset value itself.
Relnote: "Fix the behavior of SwipeableState in the case where the swipe offset is within a rounding error of an anchor."
Change-Id: I03d39d25bc376314d7197484c2a707498296aa97
Test: tested manually, leaving automated tests until swipeable rewrite
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/Swipeable.kt
an...@glovoapp.com <an...@glovoapp.com> #5
Is there any timeline for this bugfix to hit the next minor release? I can still reproduce this crash in Compose 1.0.2.
ma...@google.com <ma...@google.com> #6
I believe this has been fixed. Could you post your code that hits this issue?
an...@glovoapp.com <an...@glovoapp.com> #7
Sure.
This is the composable that uses the swipeable
Modifier:
...
Box(
Modifier.background(
backgroundColor.copy(alpha = swipeableState.toBackgroundAlpha()),
),
) {
Box(
Modifier
.fillMaxWidth()
.height(constraints.maxHeight)
.nestedScroll(nestedScrollConnection)
.swipeable(
state = swipeableState,
enabled = swipeableState.currentValue == Expanded,
anchors = mapOf(
maxHeightInPixels to Collapsed,
0f to Expanded,
),
orientation = Orientation.Vertical,
resistance = null,
thresholds = { _, _ -> FractionalThreshold(MIN_DRAG_THRESHOLD) },
)
.offset {
IntOffset(
x = 0,
y = swipeableState.offset.value.roundToInt(),
)
}
.padding(top = topSpacing)
.clip(RoundedCornerShape(topStart = Radius.S, topEnd = Radius.S))
.background(surfaceColor),
) {
Column(Modifier.fillMaxHeight()) {
Box {
header()
}
Box(Modifier.verticalScroll(scrollState)) {
body()
}
}
}
}
...
And this is the extension function that raises the exception:
@ExperimentalMaterialApi
@Composable
private fun SwipeableState<BottomSheetState>.toBackgroundAlpha(): Float {
return if (offset.value == 0f) {
MIN_BACKGROUND_ALPHA
} else {
(MIN_BACKGROUND_ALPHA - progress.fraction).coerceAtLeast(0f)
}
}
The issue comes from the access to progress.fraction
.
And here's the stacktrace:
java.util.NoSuchElementException: Key 1.8626451E-8 is missing in the map.
at kotlin.collections.MapsKt__MapWithDefaultKt.getOrImplicitDefaultNullable(MapWithDefault.kt:24)
at kotlin.collections.MapsKt__MapsKt.getValue(Maps.kt:344)
at androidx.compose.material.SwipeableState.getProgress(Swipeable.kt:275)
...
an...@glovoapp.com <an...@glovoapp.com> #9
Perfect, thanks for the heads up!
I'd prefer to wait for the next stable release and avoid the direct access to progress.fraction
for now.
Description
Jetpack Compose release version: 1.0.0-beta09
Android Studio Build: 2020.3.1 Beta4
I have a BottomSheetScaffold (which is based on Swipeable) and it randomly crashes. Our QA reports seeing these crashes on Android 11 device when pressing HOME and returning back, but I'm not sure if this is related, I got them just by navigating between screens IIRC.
Unfortunately I can't figure out the minimal case to attach as a project.
Here's the stacktrace: