Table of Contents
Device Orientation in Android Development
Learn how to handle device orientation changes gracefully, preserving user input and maintaining accessibility for users who depend on a specific device orientation due to their disability.
🎯 Why It Matters
As users rotate their devices between portrait and landscape modes, your app must adapt gracefully to maintain usability and preserve important information. Poor orientation handling can break layouts, lose user input, and create significant barriers for users who rely on specific device orientations due to their disabilities. Many users with motor impairments mount their devices in fixed positions and depend on apps working correctly in a particular orientation, making seamless orientation handling a critical accessibility requirement.
đź’» Implementation
Correct Code Example: Supporting All Orientations
Demo Description
Rather than locking orientation, support all orientations to ensure accessibility for users who mount their devices in fixed positions or rely on a specific orientation due to a disability:
<!-- AndroidManifest.xml - Support all orientations -->
<activity
android:name=".MainActivity"
android:screenOrientation="fullSensor"
android:configChanges="orientation|screenSize|screenLayout">
</activity>Code Explanation
This XML sets screenOrientation to "fullSensor" in the AndroidManifest, allowing the activity to respond to all physical orientations. Locking orientation should be avoided as it creates accessibility barriers for users who depend on a specific device orientation. The configChanges attribute ensures orientation and screen size changes are handled gracefully without restarting the activity.
Correct Code Example: Orientation-Specific Layouts
Demo Description
For complex UIs, consider creating separate layouts for portrait and landscape orientations by placing them in their respective resource directories:
res/layout/activity_main.xml (Portrait)
res/layout-land/activity_main.xml (Landscape)
<!-- res/layout-land/activity_main.xml -->
<!-- Android - Landscape-specific layout -->
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Rearranged UI elements optimised for landscape -->
</androidx.constraintlayout.widget.ConstraintLayout>Code Explanation
Android automatically selects the correct layout based on the current orientation. Placing a layout file in the layout-land directory tells Android to use it when the device is in landscape mode, while the layout directory is used for portrait mode. This allows you to optimise the UI for each orientation without complex code.
Correct Code Example: Using ConstraintLayout for Flexible Layouts
Demo Description
Here is an example of using ConstraintLayout for flexible positioning of UI elements:
<!-- Android - Flexible layout using ConstraintLayout -->
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Your UI elements here -->
</androidx.constraintlayout.widget.ConstraintLayout>Code Explanation
This XML snippet defines a ConstraintLayout that fills the entire screen. ConstraintLayout allows UI elements to be positioned flexibly and responsively, adapting naturally to both portrait and landscape orientations without requiring separate layouts.
Correct Code Example: Handling Configuration Changes
Demo Description
Here is an example of handling orientation changes without restarting the activity:
// Android - Handle orientation changes gracefully
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
// Handle landscape orientation
counterTextView.textSize = 30f
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
// Handle portrait orientation
counterTextView.textSize = 20f
}
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putInt("counter", counter)
}Code Explanation
This Kotlin code overrides onConfigurationChanged to respond to orientation changes without restarting the activity. Text size is adjusted based on the current orientation. onSaveInstanceState saves the counter value so it is preserved across configuration changes.
Correct Code Example: Preserving State During Orientation Changes
Demo Description
Here is an example of preserving important user data during orientation changes:
// Android - Save and restore user input across orientation changes
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putString("userInput", userInputEditText.text.toString())
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
savedInstanceState?.let {
userInputEditText.setText(it.getString("userInput"))
}
}Code Explanation
This Kotlin code saves the user's text input in onSaveInstanceState when an orientation change occurs. When the activity is recreated, onCreate checks for a saved state and restores the user's input, ensuring no data is lost during rotation.
Correct Code Example: Using NestedScrollView Responsibly
Demo Description
Rather than relying on two-dimensional scrolling, use NestedScrollView with a single scroll direction to keep content accessible in both orientations:
<!-- Android - Single-direction scrolling with NestedScrollView -->
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!-- Your UI elements here -->
</LinearLayout>
</androidx.core.widget.NestedScrollView>Code Explanation
This XML wraps content in a NestedScrollView with vertical scrolling only. Avoiding two-dimensional scrolling is important for accessibility—horizontal and vertical scrolling simultaneously can fail WCAG criteria and create a difficult experience for users with motor impairments or those using assistive technologies. Content should reflow vertically to accommodate different screen sizes and orientations.
âś… Best Practices
Do's
- ✓Use ConstraintLayout for flexible, responsive layouts
- ✓Create orientation-specific layouts in layout and layout-land directories
- ✓Override onConfigurationChanged to handle orientation changes gracefully
- ✓Use onSaveInstanceState or ViewModel to preserve user data
- ✓Support all orientations using fullSensor to accommodate users with disabilities
- ✓Use single-direction NestedScrollView to keep content accessible
- ✓Test with TalkBack in both portrait and landscape orientations
- ✓Ensure touch targets remain at least 48x48dp in all orientations
Don'ts
- ✗Lock screen orientation—this creates barriers for users who depend on a specific orientation
- ✗Use two-dimensional scrolling—this fails WCAG criteria and hinders assistive technology users
- âś—Allow user input to be lost during orientation changes
- âś—Use fixed pixel dimensions that break in different orientations
- ✗Assume landscape layouts are unnecessary—some users always operate in landscape
- âś—Forget to test across multiple device sizes and orientations
🔍 Common Pitfalls
Locking Orientation
Restricting an app to one orientation creates serious accessibility barriers for users who mount devices in fixed positions or have motor impairments that require a specific orientation
Two-Dimensional Scrolling
Allowing both horizontal and vertical scrolling simultaneously fails WCAG success criteria and makes content extremely difficult to navigate for users with motor impairments or assistive technology users
Lost User Input
Failing to save state during orientation changes forces users to re-enter data, which is particularly frustrating for users with motor or cognitive impairments
Broken Layouts
Using fixed dimensions instead of flexible layouts causes UI elements to overlap or become unreachable after rotation
Inconsistent Navigation Order
Changing the layout without updating the accessibility traversal order can cause TalkBack to navigate elements in a confusing sequence
Untested Landscape Mode
Many developers only test in portrait mode, leaving landscape layouts broken or inaccessible
TalkBack
Navigates elements in the order they appear in the layout. When orientation changes, the traversal order should remain logical. If using orientation-specific layouts, verify TalkBack reads elements in a sensible sequence in both orientations.
Switch Control
Switch users rely on a consistent and predictable focus order. Orientation changes should not disrupt the navigation sequence or cause focus to be lost.
Dynamic Type
Ensure text scales correctly in both orientations. Landscape mode has less vertical space, so larger text sizes should still be fully readable and not truncated.
Voice Control
Element labels should remain consistent across orientations so voice commands work reliably regardless of how the device is held.
đź§Ş Testing Steps
- 1Enable TalkBack: Settings → Accessibility → TalkBack
- 2Test portrait orientation: Navigate through the full interface and verify all elements are accessible
- 3Rotate to landscape: Verify the layout adapts correctly and TalkBack navigation remains logical
- 4Check state preservation: Enter data in a form, rotate the device, and verify no input is lost
- 5Verify touch targets: Confirm all interactive elements remain at least 48x48dp in both orientations
- 6Test with Android Emulator: Use different screen configurations to quickly test various device sizes
- 7Check scroll behaviour: Verify content scrolls in a single direction only and all content is reachable
- 8Test without screen reader: Verify layout and usability for sighted users in both orientations
Become a member to read this solution, and all of Ma11y.
This resource is part of our member knowledge base. Log in or create an account to unlock:
- Complete accessibility guidance and implementation examples
- Curated compliance frameworks and checklists
- Early access to new tools and features
