Timo Drick
02/04/2024, 1:34 PMAlbert Chang
02/04/2024, 1:44 PMTimo Drick
02/04/2024, 1:50 PMAlbert Chang
02/04/2024, 1:54 PMTimo Drick
02/04/2024, 2:17 PMFlorian Malapel
02/04/2024, 3:05 PMBoxWithConstraints
, you can access maxHeight and maxWidth, which are the values you'are looking for. Basically it's a Box
composable but it gives you data in it.
https://foso.github.io/Jetpack-Compose-Playground/foundation/layout/boxwithconstraints/Timo Drick
02/04/2024, 3:37 PMStylianos Gakis
02/04/2024, 5:02 PMTimo Drick
02/05/2024, 11:59 AMTimo Drick
02/05/2024, 12:09 PMval windowRect = remember {
val metrics = WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(ctx)
metrics.bounds
}
Thank you very much.Timo Drick
02/05/2024, 12:24 PMTimo Drick
02/05/2024, 12:37 PMStylianos Gakis
02/05/2024, 4:40 PMI do have an app with edge-to-edge design and it is very complex to get every edge cases covered. So it depends on the position of the composables if they need to have window insets padding or not. I think if i would have an insetPadding modifier that only applys padding when the composable overlapps with the window inset the code complexity would be much less.
Oh boy, that sounds like a great way to make the complexity explode 😅 The entire inset modifier system is setup in a way that if the insets were already consumed by a parent, the child will not receive those insets again. If you instead just consume the insets as the API is expecting you to, you really shouldn't have to do anything special about this, it will just work, it certainly does for our app where we use insets on all of our screens this way. Do you have an example of something not working for you to see if you're perhaps doing something else wrong?
Alex Vanyo
02/05/2024, 6:14 PMWindowMetricsCalculator.computeCurrentWindowMetrics
for calculating the current window size
There is a version in later releases of androidx.window
that takes a Context
instead of an Activity
, https://github.com/google/accompanist/pull/1576 can be a good reference.
https://issuetracker.google.com/issues/305993708 is an upstream issue for adding this as a built-in method.
displayMetrics
is almost never what you want - the size of the display does not relate to the size of your Window
Alex Vanyo
02/05/2024, 6:30 PMConfiguration
doesn’t give you the size of the window either, both due to insets and due to roundingTimo Drick
02/06/2024, 8:27 AMval screenWidth = LocalConfiguration.current.screenWidthDp.dp
val screenWidthPx = with(density) { screenWidth.toPx().toInt() }
val screenHeight = LocalConfiguration.current.screenHeightDp.dp
val screenHeightPx = with(density) { screenHeight.toPx().toInt() }
And than just add the Padding of the insets to the size. In my tests this work. But maybe i should use WindowInsets.safeDrawing for screen size calculation maybe. And than for padding i can use a different one. So all feels a little random here. Maybe the API should be a little bit more consistent here.Timo Drick
02/06/2024, 8:30 AMTimo Drick
02/06/2024, 9:06 AM@Composable
fun SmartInsetsProvider(
insets: WindowInsets,
content: @Composable @UiComposable (insetsPadding: PaddingValues) -> Unit
) {
val density = LocalDensity.current
val layoutDirection = LocalLayoutDirection.current
var insetPaddingValues by remember { mutableStateOf(PaddingValues()) }
val screenWidth = LocalConfiguration.current.screenWidthDp.dp
val screenWidthPx = with(density) { screenWidth.toPx().toInt() }
val screenHeight = LocalConfiguration.current.screenHeightDp.dp
val screenHeightPx = with(density) { screenHeight.toPx().toInt() }
Layout(content = { content(insetPaddingValues) }) { measurable, constraints ->
if (measurable.size > 1) throw IllegalArgumentException("Only one child composable allowed!")
val placeable = measurable.first().measure(constraints)
val left = insets.getLeft(density, layoutDirection)
val top = insets.getTop(density)
val bottom = insets.getBottom(density)
val right = insets.getRight(density, layoutDirection)
layout(placeable.width, placeable.height) {
coordinates?.positionInWindow()?.let { posInWindow ->
val topPaddingPx = max(0, top - posInWindow.y.toInt())
val bottomDistance = screenHeightPx + top + bottom - posInWindow.y.toInt() - placeable.height
val bottomPaddingPx = max(0, bottom - bottomDistance)
val leftPaddingPx = max(0, left - posInWindow.x.toInt())
val rightDistance = screenWidthPx + left + right - posInWindow.x.toInt() - placeable.width
val rightPaddingPx = max(0, right - rightDistance)
with(density) {
insetPaddingValues = PaddingValues.Absolute(
top = topPaddingPx.toDp(),
bottom = bottomPaddingPx.toDp(),
left = leftPaddingPx.toDp(),
right = rightPaddingPx.toDp()
)
}
}
placeable.place(IntOffset.Zero)
}
}
}
dorche
02/06/2024, 12:36 PMTimo Drick
02/06/2024, 3:11 PMTimo Drick
02/06/2024, 3:37 PMdorche
02/06/2024, 3:39 PMscreenWidthDp
and screenHeightDp
gives you the screen size, not your windowTimo Drick
02/06/2024, 3:39 PMTimo Drick
02/06/2024, 3:40 PMTimo Drick
02/06/2024, 3:41 PMTimo Drick
02/06/2024, 3:41 PMdorche
02/06/2024, 3:41 PMscreen
if it's actually window sizesTimo Drick
02/06/2024, 3:42 PMTimo Drick
02/06/2024, 3:42 PMTimo Drick
02/06/2024, 4:07 PMTimo Drick
02/06/2024, 4:09 PMvar animateStart by remember { mutableStateOf(false) }
val detailVisible by animateFloatAsState(
targetValue = if (animateStart) 1f else 0f,
label = "animation started",
animationSpec = tween(2000)
)
val animSize = 150.dp
SmartInsetsProvider(
modifier = Modifier.offset(y = animSize * detailVisible),
insets = WindowInsets.safeDrawing
) { insetPadding ->
Row(
Modifier
.background(Color.Red)
.padding(insetPadding)
.background(Color.LightGray)
.padding(8.dp)
) {
Text(
text = "Test"
)
Spacer(Modifier.width(8.dp))
Button(onClick = { animateStart = animateStart.not() }) {
Text("Animate")
}
}
}
Alex Vanyo
02/06/2024, 4:47 PMConfiguration.screen*
values are confusing: Configuration.screenWidthDp
, Configuration.screenHeightDp
Configuration.orientation
and others all refer to the window size… almost, they are different by an amount of some of the insets and by rounding. But they aren’t referring to the display size.
What was the issue with WindowMetricsCalculator.computeCurrentWindowMetrics
? That should actually give you the window size (and not an amount different by some amount of insets)Timo Drick
02/06/2024, 5:27 PMAlex Vanyo
02/06/2024, 5:28 PMcomputeCurrentWindowMetrics
? That should include the insets - if not, that’s a bugTimo Drick
02/07/2024, 8:39 AMcomputeCurrentWindowMetrics
returns a width of 2400 but usable is only 2264 even in edge-to-edge mode.Alex Vanyo
02/07/2024, 4:15 PMenableEdgeToEdge
starting with `1.9.0-alpha02`: https://developer.android.com/jetpack/androidx/releases/activity#1.9.0-alpha02
The underlying API is `layoutInDisplayCutoutMode`: setting it to https://developer.android.com/reference/android/view/WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS will allow the app to draw behind cutouts like the Pixel 7 in landscape modeAlex Vanyo
02/07/2024, 4:16 PMcomputeCurrentWindowMetrics
computes the window size - if the app is fullscreen, that’ll be the same as the screen size, but not in generalTimo Drick
02/08/2024, 9:28 AMWe’re changing that in `androidx.activity`’sNice looks good. Seems to work correctly for my solution.starting with `1.9.0-alpha02`: https://developer.android.com/jetpack/androidx/releases/activity#1.9.0-alpha02enableEdgeToEdge
Timo Drick
03/14/2024, 4:47 PM@Composable
fun getWindowSize(): IntSize {
val view = LocalView.current
return remember {
val windowWidth = view.rootView.width
val windowHeight = view.rootView.height
IntSize(windowWidth, windowHeight)
}
}
Alex Vanyo
03/14/2024, 5:22 PMLocalView
fills up the entire window size
• That won’t return updated sizes when the window size changesTimo Drick
03/14/2024, 5:25 PM