Mastering Device Orientation Detection in Jetpack Compose
Let’s assume you fixed the screen’s orientation to portrait
or landscape
like below,
activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
Then this solution will not work and LocalConfiguration.current.orientation
will always return Configuration.ORIENTATION_PORTRAIT
even the user rotated the device horizontally.
Because the screen orientation is fixed to portrait, not the device orientation.
In this blog post, we’ll delve into how to detect device orientation in Android using the OrientationListener.
What is OrientationListener?
OrientationListener is a class provided by the Android framework that allows developers to monitor changes in device orientation. By registering an OrientationListener with the system, your app can receive updates whenever the device orientation changes, such as when the user rotates their device from portrait to landscape or vice versa.
Implementing Orientation Detection
Let’s start by creating a composable that sets up an OrientationEventListener
and displays different content based on the orientation.
Step 1: Create the OrientationListener
First, we need to create an OrientationEventListener
through a DisposableEffect
that will notify us when the device's orientation changes.
@Composable
fun DeviceOrientationListener(applicationContext: Context, onOrientationChange: (DeviceOrientation) -> Unit) {
DisposableEffect(Unit) {
val orientationEventListener = object : OrientationEventListener(applicationContext) {
override fun onOrientationChanged(orientation: Int) {
if (orientation >= 350 || orientation < 10) {
onOrientationChange(DeviceOrientation.DEVICE_ORIENTATION_PORTRAIT)
} else if (orientation in 80..159) {
onOrientationChange(DeviceOrientation.DEVICE_ORIENTATION_REVERSE_LANDSCAPE)
} else if (orientation in 200..289) {
onOrientationChange(DeviceOrientation.DEVICE_ORIENTATION_LANDSCAPE)
}
}
}
orientationEventListener.enable()
// Disable the event onDispose
onDispose {
orientationEventListener.disable()
}
}
}
Step 2: Create the Composable Function
Next, we’ll create a composable function that sets up the OrientationEventListener
and reacts to orientation changes.
import android.content.Context
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
@Composable
fun OrientationAwareContent() {
val context = LocalContext.current
var orientation by remember { mutableStateOf(DeviceOrientation.DEVICE_ORIENTATION_PORTRAIT) }
val applicationContext = LocalContext.current.applicationContext
DeviceOrientationListener(applicationContext) { orientation = it }
if (orientation == DeviceOrientation.DEVICE_ORIENTATION_LANDSCAPE) {
// Content to show in landscape mode
LandscapeContent()
} else {
// Content to show in portrait mode
PortraitContent()
}
}
@Composable
fun PortraitContent() {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text(text = "Portrait Mode", style = MaterialTheme.typography.h4)
}
}
@Composable
fun LandscapeContent() {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text(text = "Landscape Mode", style = MaterialTheme.typography.h4)
}
}
Step 3: Handling Orientation Changes
In our OrientationAwareContent
composable, we initialize the DeviceOrientationListener
and enable it when the composable enters the composition. We disable the listener when the composable leaves the composition to avoid memory leaks. (That’s the beauty of DisposableEffect)
We use the orientation
state to keep track of the current orientation and display different content based on whether the device is in portrait or landscape mode.
Step 4: Creating the Main Activity
Finally, we set up our MainActivity
to display the OrientationAwareContent
composable.
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import com.example.orientationlistener.ui.theme.OrientationListenerTheme
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
OrientationListenerTheme {
OrientationAwareContent()
}
}
}
}
@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
OrientationListenerTheme {
OrientationAwareContent()
}
}
Conclusion
Detecting and handling device orientation changes in Jetpack Compose is straightforward with the OrientationEventListener
. By setting up an OrientationEventListener
within a composable and responding to orientation changes, we can create responsive and adaptive UI layouts that enhance the user experience.
This approach ensures that our app reacts dynamically to orientation changes, providing a seamless and engaging user experience. Try integrating this into your Jetpack Compose project and see how it improves your app’s responsiveness.