Re-gaining orientation #4
Tags: android, kotlin, jetpackcompose
Published: 2021-04-01 13:00:53

Welcome to the final episode of *Re-gaining orientation*. Please recall that in this mini series we focussed on changes to device orientation and how that is covered in Jetpack Compose. We also looked at foldables and investigated how opening and closing the device should change your composables hierarchy.

On traditional tablets (and smartphones in landscape mode) my sample app has a typical two-column-view where the left part is a list and therefore is narrower than the content part at the right hand side. On a foldable with a noticeable hinge it might make more sense to divide the screen into two equal-sized parts. We can use the Jetpack Window Manager component to check if the device has a so-called `FoldingFeature`. However, I concluded the previous post by saying

> While both results look quite pretty we have a few thing to do.
> Can you guess what?

The problem is that on both the stock Android emulator (acting as a foldable) and the Surface Duo Emulator parts of the screen content are not visible - because of the fold or hinge.

![A simulated hinge covers a portion of the screen](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q3rlcllfadeklxho8cop.png)

Fortunately it is easy to determine both position and size of the covered area:

```kotlin
(feature as FoldingFeature).run {
  if (isSeparating) {
    weightModuleSelection = 0.5F
    weightModule = 0.5F
    width = bounds.width()
  }
}
```

`bounds` is an ordinary android.graphics.Rect, so we can obtain its width with, well, `width()`. My `width` variable looks like this:

```kotlin
private var width by mutableStateOf(0)
```

To make use of it in my sample code I need to add just one line. Can you spot it?

```kotlin
@Composable
fun Landscape(
    module: MutableState<Module?>,
    weightModuleSelection: Float,
    weightModule: Float
) {
    Row(modifier = Modifier.fillMaxSize()) {
        ModuleSelection(
            module = module,
            modifier = Modifier.weight(weight = weightModuleSelection)
        )
        Spacer(modifier = Modifier.width(LocalDensity.current.run { width.toDp() }))
        module.value?.let {
            Module(
                module = it,
                modifier = Modifier.weight(weightModule)
            )
        }
    }
}
```

`Spacer()` is a composable...

> that represents an empty space layout, whose size can
> be defined using `Modifier.width`, `Modifier.height` and
> `Modifier.size` modifiers.

Please note that we must convert the pixel values to `dp`. Here's how my sample app looks like after these changes:

![Sample app honoring the hinge](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zs1fhhyx0gfsvkr3l8kp.png)

You may be wondering why it takes just a `Spacer()` to make things work. Well, both the module selection (the list) and the module (the content) get their width through `Modifier.weight`. While computing these values, Compose takes into account the width of other composables that have not specified a weight - like the `Spacer()`. If the app is run an a device that has no `FoldingFeature` its size remains 0.

Clever, isn't it`? 😎 I will be briefly mentioning an alternative, nonetheless. That's because my solution assumes that the hinge or fold is in the middle of the screen. Please recall that this was the preliminary idea - to split the display into two equal-sized areas. But what if this is not the case? What if the designer wants a device that folds at a 30 : 70 ratio?

Please recall that the `FoldingFeature` gives us the `bounds` rectangle. So far we only used its width. But we can access its `left` attribute to compute how big the area at the left hand side of the fold is. If `left` is, say 800, we know that (for example) the module selection in my example should be this wide. Hence, instead of using `Modifier.weight()` we just use `Modifier.width()` like in the `Spacer()`.

This concludes my musings about screen orientation and foldables. Anything else you would like to see covered? Please do share your thoughts in the comments.

---

[Source](https://github.com/tkuenneth/android-demos/tree/master/compose/ScreenSizeDemo)