Android Jetpack Compose Screen Orientation Control

Published May 26, 2025

Learn how to implement programmatic screen orientation changes in Android Jetpack Compose applications with this comprehensive guide featuring practical code examples and best practices.

Table of Contents

Introduction to Jetpack Compose Screen Orientation Control

Android Jetpack Compose screen orientation management is a crucial aspect of modern Android development. With the increasing demand for responsive mobile applications, developers need to understand how to programmatically control screen orientation in their Compose applications.

This tutorial covers everything you need to know about Compose orientation control, from basic implementation to advanced sensor-based orientation handling. Whether you're building a media app that requires landscape mode or a form-heavy application that works best in portrait, mastering screen orientation in Jetpack Compose is essential.

Why Screen Orientation Control Matters

Compose screen rotation control enhances user experience by:

  • Providing optimal viewing angles for different content types
  • Preventing unwanted orientation changes during user interactions
  • Enabling immersive experiences in games and media applications
  • Maintaining form data integrity during orientation changes

Implementing Screen Orientation Control in Jetpack Compose

To implement programmatic screen orientation changes in your Compose application, you'll need to work with Android's Activity class and the ActivityInfo orientation constants. Here's how to set up Compose orientation management in your project.

Prerequisites for Compose Screen Orientation

Before implementing screen orientation control in Android Compose, ensure your project includes:

  • Android Jetpack Compose dependencies
  • Material 3 design components
  • Proper AndroidManifest.xml configuration
  • Activity lifecycle management
AndroidManifest.xml Configuration:
<activity
    android:name=".MainActivity"
    android:configChanges="orientation|screenSize|keyboardHidden"
    android:exported="true">
</activity>

Types of Screen Orientation in Jetpack Compose

Understanding different Android screen orientation types is crucial for effective Compose rotation control. Here are the main orientation modes you can implement:

Fixed Orientations

  • Portrait Lock: Keeps screen in vertical position
  • Landscape Lock: Forces horizontal orientation
  • Reverse Portrait: Upside-down vertical orientation
  • Reverse Landscape: 180° rotated horizontal view

Sensor-Based Orientations

  • Sensor Portrait: Normal and reverse portrait
  • Sensor Landscape: Both landscape orientations
  • Full Sensor: All four orientations
  • Auto Rotation: System default behavior

Complete Jetpack Compose Screen Orientation Example

This Compose screen orientation tutorial provides a working example that demonstrates all aspects of programmatic orientation control. The application includes buttons for each orientation type and real-time feedback.

Key Features of the Compose Orientation App

  • Interactive orientation controls for all screen positions
  • Real-time orientation status display using Compose state
  • Material 3 design implementation with responsive UI
  • Comprehensive orientation testing environment
  • Best practices demonstration for production apps

Implementation Highlights

The Compose orientation controller demonstrates:

  • Using ActivityInfo constants for screen rotation control
  • Managing orientation state with Compose remember
  • Creating responsive UI that adapts to orientation changes
  • Implementing user-friendly controls for orientation switching

 

// MainActivity.kt
package com.example.orientationcontroller

import android.content.pm.ActivityInfo
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            OrientationControllerTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    OrientationControllerScreen()
                }
            }
        }
    }
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun OrientationControllerScreen() {
    val context = LocalContext.current
    val activity = context as ComponentActivity
    var currentOrientation by remember { mutableStateOf("Auto") }
    
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp)
            .verticalScroll(rememberScrollState()),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.spacedBy(16.dp)
    ) {
        // Header
        Text(
            text = "Screen Orientation Controller",
            fontSize = 24.sp,
            fontWeight = FontWeight.Bold,
            textAlign = TextAlign.Center,
            modifier = Modifier.padding(vertical = 16.dp)
        )
        
        // Current orientation display
        Card(
            modifier = Modifier.fillMaxWidth(),
            colors = CardDefaults.cardColors(
                containerColor = MaterialTheme.colorScheme.primaryContainer
            )
        ) {
            Column(
                modifier = Modifier.padding(16.dp),
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                Text(
                    text = "Current Orientation",
                    style = MaterialTheme.typography.titleMedium,
                    fontWeight = FontWeight.SemiBold
                )
                Spacer(modifier = Modifier.height(8.dp))
                Text(
                    text = currentOrientation,
                    style = MaterialTheme.typography.headlineSmall,
                    color = MaterialTheme.colorScheme.primary,
                    fontWeight = FontWeight.Bold
                )
            }
        }
        
        // Orientation control buttons
        Text(
            text = "Control Orientation",
            style = MaterialTheme.typography.titleLarge,
            fontWeight = FontWeight.SemiBold
        )
        
        // Portrait orientation
        Button(
            onClick = { 
                activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
                currentOrientation = "Portrait"
            },
            modifier = Modifier.fillMaxWidth()
        ) {
            Text("Lock to Portrait")
        }
        
        // Landscape orientation
        Button(
            onClick = { 
                activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
                currentOrientation = "Landscape"
            },
            modifier = Modifier.fillMaxWidth()
        ) {
            Text("Lock to Landscape")
        }
        
        // Reverse Portrait
        Button(
            onClick = { 
                activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT
                currentOrientation = "Reverse Portrait"
            },
            modifier = Modifier.fillMaxWidth()
        ) {
            Text("Lock to Reverse Portrait")
        }
        
        // Reverse Landscape
        Button(
            onClick = { 
                activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
                currentOrientation = "Reverse Landscape"
            },
            modifier = Modifier.fillMaxWidth()
        ) {
            Text("Lock to Reverse Landscape")
        }
        
        // Sensor-based orientations
        Divider(modifier = Modifier.padding(vertical = 8.dp))
        
        Text(
            text = "Sensor-Based Controls",
            style = MaterialTheme.typography.titleMedium,
            fontWeight = FontWeight.SemiBold
        )
        
        // Sensor Portrait
        OutlinedButton(
            onClick = { 
                activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
                currentOrientation = "Sensor Portrait"
            },
            modifier = Modifier.fillMaxWidth()
        ) {
            Text("Sensor Portrait (Portrait + Reverse)")
        }
        
        // Sensor Landscape
        OutlinedButton(
            onClick = { 
                activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
                currentOrientation = "Sensor Landscape"
            },
            modifier = Modifier.fillMaxWidth()
        ) {
            Text("Sensor Landscape (Landscape + Reverse)")
        }
        
        // Full Sensor
        OutlinedButton(
            onClick = { 
                activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
                currentOrientation = "Full Sensor"
            },
            modifier = Modifier.fillMaxWidth()
        ) {
            Text("Full Sensor (All 4 orientations)")
        }
        
        // Auto/System default
        FilledTonalButton(
            onClick = { 
                activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
                currentOrientation = "Auto (System Default)"
            },
            modifier = Modifier.fillMaxWidth()
        ) {
            Text("Reset to Auto")
        }
        
        // Information card
        Card(
            modifier = Modifier
                .fillMaxWidth()
                .padding(top = 16.dp),
            colors = CardDefaults.cardColors(
                containerColor = MaterialTheme.colorScheme.surfaceVariant
            )
        ) {
            Column(
                modifier = Modifier.padding(16.dp)
            ) {
                Text(
                    text = "How it works:",
                    style = MaterialTheme.typography.titleSmall,
                    fontWeight = FontWeight.SemiBold
                )
                Spacer(modifier = Modifier.height(8.dp))
                Text(
                    text = "• Portrait/Landscape: Locks to specific orientation\n" +
                          "• Reverse: Locks to 180° rotated orientations\n" +
                          "• Sensor Portrait/Landscape: Allows sensor rotation within orientation family\n" +
                          "• Full Sensor: Allows all 4 orientations based on sensor\n" +
                          "• Auto: Uses system default behavior",
                    style = MaterialTheme.typography.bodyMedium,
                    lineHeight = 20.sp
                )
            }
        }
    }
}

@Composable
fun OrientationControllerTheme(content: @Composable () -> Unit) {
    MaterialTheme(
        colorScheme = lightColorScheme(),
        content = content
    )
}

// AndroidManifest.xml additions needed:
/*
<uses-permission android:name="android.permission.WRITE_SETTINGS" />

In your activity declaration:
<activity
    android:name=".MainActivity"
    android:configChanges="orientation|screenSize|keyboardHidden"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
*/

// build.gradle.kts (Module: app) dependencies:
/*
dependencies {
    implementation("androidx.core:core-ktx:1.12.0")
    implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
    implementation("androidx.activity:activity-compose:1.8.2")
    implementation(platform("androidx.compose:compose-bom:2023.10.01"))
    implementation("androidx.compose.ui:ui")
    implementation("androidx.compose.ui:ui-graphics")
    implementation("androidx.compose.ui:ui-tooling-preview")
    implementation("androidx.compose.material3:material3")
}
*/

 

Best Practices for Compose Screen Orientation

Follow these Android orientation best practices when implementing screen rotation in Jetpack Compose:

Performance Optimization

  • Use configChanges in AndroidManifest to prevent activity recreation
  • Implement proper state management for Compose orientation changes
  • Consider using rememberSaveable for persistent state
  • Optimize layouts for both portrait and landscape orientations

User Experience Guidelines

  • Provide clear visual feedback during orientation transitions
  • Ensure content remains accessible in all orientations
  • Test screen orientation behavior on various device sizes
  • Consider user preferences for auto-rotation settings

Troubleshooting Compose Screen Orientation Issues

Common problems with Jetpack Compose screen orientation and their solutions:

Activity Recreation Problems

If your app restarts during orientation changes in Compose, ensure you've added the correct configChanges attribute in your AndroidManifest.xml file.

State Loss During Rotation

Use Compose's rememberSaveable instead of remember for state that should survive screen rotation events.

Orientation Not Changing

Check that your device's auto-rotation is enabled and that you're using the correct ActivityInfo constants for programmatic orientation control.

Mastering Screen Orientation in Jetpack Compose

Jetpack Compose screen orientation control is an essential skill for Android developers creating modern, responsive applications. This tutorial has covered everything from basic orientation locking to advanced sensor-based rotation handling.

By implementing the techniques shown in this Compose orientation tutorial, you can create applications that provide optimal user experiences across all device orientations. Remember to test your screen orientation implementation thoroughly on various devices and screen sizes.

Next Steps

Continue improving your Android Compose development skills by:

  • Exploring adaptive layouts for different screen orientations
  • Implementing custom orientation animations
  • Creating orientation-aware navigation patterns
  • Building responsive designs that work across all orientations

Start implementing programmatic screen orientation control in your Jetpack Compose applications today and enhance your users' mobile experience!