I'm having some issues returning from Immersive Mode in an ActionBarActivity
. I have created a simple app to illustrate this issue. There is a layout with a single button to toggle immersive mode. When "returning" from immersive mode, the action bar is offset downwards from its original position, roughly the same distance again that it is usually offset from the top of the screen.
I've tried this on a Nexus 4 running Lollipop. This behavior did not happen pre-Lollipop.
Screenshots before, immersed, after.
A simple ActionBarActivity
that illustrates this issue:
public class MainActivity extends ActionBarActivity { private boolean immersed; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @TargetApi(Build.VERSION_CODES.KITKAT) private void enterImmersiveMode() { if(android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { getWindow().getDecorView().setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY ); immersed = true; } } @TargetApi(Build.VERSION_CODES.KITKAT) private void leaveImmersiveMode() { if(android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); immersed = false; // recreate(); } } public void toggleImmersive(View v) { if (immersed) { leaveImmersiveMode(); } else { enterImmersiveMode(); } } }
Nothing fancy in the manifest:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.immersivetest" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="21" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="ImmersiveTest" android:theme="@style/Theme.AppCompat" > <activity android:name=".MainActivity" android:label="ImmersiveTest" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
Trivial layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.immersivetest.MainActivity" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:text="toggle immersive" android:onClick="toggleImmersive" /> </RelativeLayout>
The workaround I use at the moment is to call recreate()
after leaving immersive mode, but it looks a bit "glitchy".
If I up the minSdkVersion
and use Activity
instead of ActionBarActivity
, i.e. don't use the support library, then I do not experience this behavior.
I understand that immersive mode is only available in KitKat+ and that I don't need to use the ActionBarActivity
from the support library, but the finished product will have to run on API versions 8+ and the immersive mode is an optional extra.
Some other workarounds I have thought about and dismissed for now:
Activity
which immediately forwards programmatically to an ActionBarActivity
for lower API versions.Either of those options sounds like a lot of added maintenance.
Is there anything else I could try? Are there any glaring mistakes in the code above, with respect to returning from immersive mode?
Update
I have since updated the Nexus 4 to 5.1 and the support library to rev 22.1.1 and the behavior is still the same. I have also updated the code to use the new AppCompatActivity
since ActionBarActivity
is now deprecated. The behavior is, once more, the same.
public class MainActivity extends AppCompatActivity { // no changes here }
Update
This weird behavior also extends to the landscape mode. In addition to the offset at the top of the screen, there also is an offset to the right of the screen between the end of the action bar and the navigation buttons. Interestingly this offset again seems to be the size of the navigation button "bar", i.e. larger than the offset at the top.
Landscape screenshots before, immersed, after.
To replace an app's default action bar with a Toolbar : Create a new custom theme and modify the app's properties so that it uses this new theme. Disable the windowActionBar attribute in the custom theme and enable the windowNoTitle attribute. Define a layout for the Toolbar .
All action buttons and other items available in the action overflow are defined in an XML menu resource. To add actions to the action bar, create a new XML file in your project's res/menu/ directory. The app:showAsAction attribute specifies whether the action should be shown as a button on the app bar.
Had the same problem, fixed with this: your leaveImmersiveMode()
function should use these flags instead:
getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_FULLSCREEN);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With