Katie McCormick | 467f5db | 2013-11-05 13:35:15 -0800 | [diff] [blame] | 1 | page.title=Using Immersive Full-Screen Mode |
| 2 | |
| 3 | trainingnavtop=true |
| 4 | |
| 5 | @jd:body |
| 6 | |
| 7 | <div id="tb-wrapper"> |
| 8 | <div id="tb"> |
| 9 | |
| 10 | <!-- table of contents --> |
| 11 | <h2>This lesson teaches you to</h2> |
| 12 | <ol> |
| 13 | <li><a href="#compare">Choose an Approach</a></li> |
Katie McCormick | 9dd04e7 | 2013-11-18 11:02:42 -0800 | [diff] [blame] | 14 | <li><a href="#nonsticky">Use Non-Sticky Immersion</a></li> |
| 15 | <li><a href="#sticky">Use Sticky Immersion</a></li> |
Katie McCormick | 467f5db | 2013-11-05 13:35:15 -0800 | [diff] [blame] | 16 | </ol> |
| 17 | |
| 18 | |
| 19 | <!-- other docs (NOT javadocs) --> |
| 20 | <h2>You should also read</h2> |
| 21 | |
| 22 | <ul> |
| 23 | <li> |
| 24 | <a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> API Guide |
| 25 | </li> |
| 26 | <li> |
| 27 | <a href="{@docRoot}design/patterns/fullscreen.html"> |
| 28 | Android Design Guide |
| 29 | </a> |
| 30 | </li> |
| 31 | </ul> |
| 32 | |
| 33 | |
| 34 | |
| 35 | <h2>Try it out</h2> |
| 36 | |
| 37 | <div class="download-box"> |
| 38 | <a href="{@docRoot}samples/ImmersiveMode/index.html" |
| 39 | class="button">Get the sample</a> |
| 40 | <p class="filename">ImmersiveMode sample</p> |
| 41 | </div> |
| 42 | |
| 43 | </div> |
| 44 | </div> |
| 45 | |
| 46 | <a class="notice-developers-video wide" href="http://www.youtube.com/watch?v=cBi8fjv90E4"> |
| 47 | <div> |
| 48 | <h3>Video</h3> |
| 49 | <p>DevBytes: Android 4.4 Immersive Mode</p> |
| 50 | </div> |
| 51 | </a> |
| 52 | |
| 53 | <p>Android 4.4 (API Level 19) introduces a new |
| 54 | {@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE} flag for |
| 55 | {@link android.view.View#setSystemUiVisibility setSystemUiVisibility()} that lets your app |
| 56 | go truly "full screen." This flag, when combined with the |
| 57 | {@link android.view.View#SYSTEM_UI_FLAG_HIDE_NAVIGATION} and |
| 58 | {@link android.view.View#SYSTEM_UI_FLAG_FULLSCREEN} flags, hides the navigation and status |
| 59 | bars and lets your app capture all touch events on the screen.</p> |
| 60 | |
| 61 | <p>When immersive full-screen mode is |
| 62 | enabled, your activity continues to receive all touch events. The user can reveal the |
| 63 | system bars with an inward swipe along the region where the system bars normally appear. |
| 64 | This clears the {@link android.view.View#SYSTEM_UI_FLAG_HIDE_NAVIGATION} flag |
| 65 | (and the {@link android.view.View#SYSTEM_UI_FLAG_FULLSCREEN} flag, if applied) so the |
| 66 | system bars become visible. This also triggers your |
| 67 | {@link android.view.View.OnSystemUiVisibilityChangeListener}, |
| 68 | if set. However, if you'd like the system bars to automatically hide |
| 69 | again after a few moments, you can instead use the |
| 70 | {@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE_STICKY} flag. Note that the |
| 71 | "sticky" version of the flag doesn't trigger any listeners, as system bars temporarily |
| 72 | shown in this mode are in a transient state. |
| 73 | </p> |
| 74 | |
Katie McCormick | 467f5db | 2013-11-05 13:35:15 -0800 | [diff] [blame] | 75 | <p>Figure 1 illustrates the different "immersive mode" states:</p> |
| 76 | |
| 77 | <img src="{@docRoot}images/training/imm-states.png" |
| 78 | alt="system bars"> |
| 79 | <p class="img-caption"><strong>Figure 1.</strong> Immersive mode states.</p> |
| 80 | |
| 81 | <p>In figure 1:</p> |
| 82 | <ol> |
| 83 | <li><strong>Non-immersive mode</strong>—This is how the app |
| 84 | appears before it enters immersive mode. It is also how the app appears if you use the |
| 85 | {@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE IMMERSIVE} flag, and the user swipes to |
| 86 | display the system bars, thereby clearing the {@link android.view.View#SYSTEM_UI_FLAG_HIDE_NAVIGATION} and |
| 87 | {@link android.view.View#SYSTEM_UI_FLAG_FULLSCREEN} flags. Once these flags are cleared, the system |
| 88 | bars reappear and remain visible.</li> |
| 89 | |
| 90 | <p>Note that it's best practice to |
| 91 | keep all UI controls in sync with the system bars, to minimize the |
| 92 | number of states your screen can be in. This provides a more seamless user experience. So |
| 93 | here all UI controls are displayed along with the status bars. Once the app enters |
| 94 | immersive mode, the UI controls are hidden along with the system bars. |
| 95 | To ensure that your UI visibility stays in sync with system bar visibility, make sure to |
| 96 | provide an appropriate {@link android.view.View.OnSystemUiVisibilityChangeListener} |
| 97 | to watch for changes, as described in |
| 98 | <a href="visibility.html">Responding to UI Visibility Changes</a>.</p></li> |
| 99 | |
| 100 | <li><strong>Reminder bubble</strong>—The system displays a reminder bubble |
| 101 | the first time users enter |
| 102 | immersive mode in your app. The reminder bubble reminds users how to display |
| 103 | the system bars. |
| 104 | <p class="note"><strong>Note:</strong> If you want to force the reminder bubble to appear |
| 105 | for testing purposes, you can do so by putting the app in immersive mode, turning off the |
| 106 | screen with the power button, and then turning the screen back on again within 5 seconds. |
| 107 | </p></li> |
| 108 | |
| 109 | <li><strong>Immersive mode</strong>—This is the app in immersive mode, with the |
| 110 | system bars and other UI controls hidden. You can achieve this state with either |
| 111 | {@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE IMMERSIVE} or |
| 112 | {@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE_STICKY IMMERSIVE_STICKY}. </li> |
| 113 | |
| 114 | <li><strong>Sticky flag</strong>—This is the UI you see if you use the |
| 115 | {@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE_STICKY IMMERSIVE_STICKY} flag, |
| 116 | and the user swipes to display the system bars. Semi-transparent bars temporarily appear and then |
| 117 | hide again. The act of swiping doesn't clear any flags, nor does it trigger your |
| 118 | system UI visibility change listeners, because the transient appearance of the system bars isn't |
| 119 | considered a UI visibility change.</li> |
| 120 | </ol> |
| 121 | |
| 122 | <p class="note"><strong>Note:</strong> Remember that the "immersive" flags only take effect |
| 123 | if you use them in conjunction with {@link android.view.View#SYSTEM_UI_FLAG_HIDE_NAVIGATION}, |
| 124 | {@link android.view.View#SYSTEM_UI_FLAG_FULLSCREEN}, or |
| 125 | both. You can just use one or the other, but it's common to hide both the status and the |
| 126 | navigation bar when you're implementing "full immersion" mode.</p> |
| 127 | |
| 128 | <h2 id="compare">Choose an Approach</h2> |
| 129 | |
| 130 | <p>The flags {@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE} and |
| 131 | {@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE_STICKY} both provide an immersive |
Katie McCormick | 9dd04e7 | 2013-11-18 11:02:42 -0800 | [diff] [blame] | 132 | experience, but with the differences in behavior described above. Here are |
| 133 | examples of when you would use one flag vs. the other:</p> |
Katie McCormick | 467f5db | 2013-11-05 13:35:15 -0800 | [diff] [blame] | 134 | |
| 135 | <ul> |
| 136 | <li>If you're building a book reader, news reader, or a magazine, use |
| 137 | the {@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE IMMERSIVE} flag in conjunction |
| 138 | with {@link android.view.View#SYSTEM_UI_FLAG_FULLSCREEN} and |
| 139 | {@link android.view.View#SYSTEM_UI_FLAG_HIDE_NAVIGATION}. Because users may want to access |
| 140 | the action bar and other UI controls somewhat frequently, but not be bothered with any UI |
| 141 | elements while flipping through content, |
| 142 | {@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE IMMERSIVE} is a good option for this |
| 143 | use case.</li> |
| 144 | |
| 145 | <li>If you're building a truly immersive app, where you expect users to interact near |
| 146 | the edges of the screen and you don't expect them to need frequent access to the system |
| 147 | UI, use the |
| 148 | {@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE_STICKY IMMERSIVE_STICKY} flag |
| 149 | in conjunction with {@link android.view.View#SYSTEM_UI_FLAG_FULLSCREEN} and |
| 150 | {@link android.view.View#SYSTEM_UI_FLAG_HIDE_NAVIGATION}. For example, this approach |
| 151 | might be suitable for a game or a drawing app.</li> |
| 152 | |
| 153 | <li>If you're building a video player or some other app that requires minimal user |
| 154 | interaction, you can probably get by with the <a href="{@docRoot}design/patterns/fullscreen.html"> |
| 155 | lean back</a> approach, available since |
| 156 | Android 4.0 (API Level 14). For this type of app, simply using |
| 157 | {@link android.view.View#SYSTEM_UI_FLAG_FULLSCREEN} |
| 158 | and {@link android.view.View#SYSTEM_UI_FLAG_HIDE_NAVIGATION} should be |
| 159 | sufficient. Don't use the "immersive" flags in this case.</li> |
| 160 | </ul> |
| 161 | |
Katie McCormick | 9dd04e7 | 2013-11-18 11:02:42 -0800 | [diff] [blame] | 162 | <h2 id="nonsticky">Use Non-Sticky Immersion</h2> |
Katie McCormick | 467f5db | 2013-11-05 13:35:15 -0800 | [diff] [blame] | 163 | |
| 164 | <p>When you use the {@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE} flag, it hides |
| 165 | the system bars based on what other UI flags you have set |
| 166 | ({@link android.view.View#SYSTEM_UI_FLAG_HIDE_NAVIGATION}, |
| 167 | {@link android.view.View#SYSTEM_UI_FLAG_FULLSCREEN}, or |
| 168 | both). When the user swipes inward in a system bars region, the |
| 169 | system bars reappear and remain visible.</p> |
| 170 | |
| 171 | <p>It's good practice to include other system UI flags (such as |
| 172 | {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} and |
| 173 | {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_STABLE}) to keep the content from resizing |
| 174 | when the system bars hide and show. You should also make sure that the action bar and other |
| 175 | UI controls are hidden at the same time. This snippet demonstrates how to hide and show the |
| 176 | status and navigation bars, without resizing the content:</p> |
| 177 | |
| 178 | <pre> |
| 179 | // This snippet hides the system bars. |
| 180 | private void hideSystemUI() { |
| 181 | // Set the IMMERSIVE flag. |
| 182 | // Set the content to appear under the system bars so that the content |
| 183 | // doesn't resize when the system bars hide and show. |
| 184 | mDecorView.setSystemUiVisibility( |
| 185 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
| 186 | | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
| 187 | | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
| 188 | | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar |
| 189 | | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar |
| 190 | | View.SYSTEM_UI_FLAG_IMMERSIVE); |
| 191 | } |
| 192 | |
| 193 | // This snippet shows the system bars. It does this by removing all the flags |
| 194 | // except for the ones that make the content appear under the system bars. |
| 195 | private void showSystemUI() { |
| 196 | mDecorView.setSystemUiVisibility( |
| 197 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
| 198 | | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
| 199 | | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); |
| 200 | } |
| 201 | </pre> |
| 202 | |
| 203 | |
| 204 | <p>You may also want to implement the following in conjunction with the |
| 205 | {@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE IMMERSIVE} flag to provide a better user |
| 206 | experience:</p> |
| 207 | |
| 208 | <ul> |
| 209 | <li>Register a listener so that your app can get notified of system UI visibility changes, |
| 210 | as described in <a href="visibility.html">Responding to UI Visibility Changes</a>.</li> |
| 211 | |
| 212 | <li>Implement {@link android.app.Activity#onWindowFocusChanged onWindowFocusChanged()}. |
| 213 | If you gain window focus, you may want to re-hide the system bars. |
| 214 | If you lose window focus, for example due to a dialog or pop up menu showing above your app, |
| 215 | you'll probably want to cancel any pending "hide" operations you previously scheduled |
| 216 | with {@link android.os.Handler#postDelayed Handler.postDelayed()} or something similar.</li> |
| 217 | |
| 218 | <li>Implement a {@link android.view.GestureDetector} that detects |
| 219 | {@link android.view.GestureDetector.OnGestureListener#onSingleTapUp}, to allow users to |
| 220 | manually toggle the visibility of the system bars by touching your content. |
| 221 | Simple click listeners aren't the best solution for this because they get triggered even |
| 222 | if the user drags a finger across the screen (assuming the click target takes up the whole |
| 223 | screen). |
| 224 | </li> |
| 225 | |
| 226 | </ul> |
| 227 | |
| 228 | <p> |
| 229 | For more discussion of these topics, watch the video |
| 230 | <a class ="external-link" href="http://www.youtube.com/embed/cBi8fjv90E4">DevBytes: |
| 231 | Android 4.4 Immersive Mode</a>.</p> |
| 232 | |
Katie McCormick | 9dd04e7 | 2013-11-18 11:02:42 -0800 | [diff] [blame] | 233 | <h2 id="sticky">Use Sticky Immersion</h2> |
Katie McCormick | 467f5db | 2013-11-05 13:35:15 -0800 | [diff] [blame] | 234 | |
| 235 | <p>When you use the {@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE_STICKY} flag, |
| 236 | an inward swipe in the system bars areas causes the bars to temporarily appear in a |
| 237 | semi-transparent state, but no flags are cleared, and your |
| 238 | system UI visibility change listeners are not triggered. The bars |
| 239 | automatically hide again after a short delay, or if the user interacts with the middle of the |
| 240 | screen.</p> |
| 241 | |
| 242 | <p>Figure 2 shows the semi-transparent system bars that briefly appear and then hide again |
| 243 | when you use the {@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE_STICKY IMMERSIVE_STICKY} flag.</p> |
| 244 | |
| 245 | <img src="{@docRoot}images/training/imm-sticky.png" |
| 246 | alt="system bars"> |
| 247 | <p class="img-caption"><strong>Figure 2.</strong> Auto-hiding system bars.</p> |
| 248 | |
| 249 | <p>Below is a simple approach to using this flag. Any time the window receives focus, simply |
| 250 | set the {@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE_STICKY IMMERSIVE_STICKY} flag, along |
| 251 | with the other flags discussed in <a href="#nonsticky">Use IMMERSIVE</a>. For example:</p> |
| 252 | |
| 253 | <pre> |
| 254 | @Override |
| 255 | public void onWindowFocusChanged(boolean hasFocus) { |
| 256 | super.onWindowFocusChanged(hasFocus); |
| 257 | if (hasFocus) { |
| 258 | decorView.setSystemUiVisibility( |
| 259 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
| 260 | | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
| 261 | | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
| 262 | | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
| 263 | | View.SYSTEM_UI_FLAG_FULLSCREEN |
| 264 | | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);} |
| 265 | } |
| 266 | </pre> |
| 267 | |
| 268 | <p class="note"><strong>Note:</strong> If you like the auto-hiding behavior of |
| 269 | {@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE_STICKY IMMERSIVE_STICKY} |
| 270 | but need to show your own UI controls as well, just use |
| 271 | {@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE IMMERSIVE} combined with |
| 272 | {@link android.os.Handler#postDelayed Handler.postDelayed()} or something similar to |
| 273 | re-enter immersive mode after a few seconds.</p> |