Панель действий отображается неправильно при возвращении из режима погружения

У меня возникают некоторые проблемы с возвращением из режима погружения в ActionBarActivity, Я создал простое приложение, чтобы проиллюстрировать эту проблему. Есть макет с одной кнопкой для переключения в режиме погружения. При "возврате" из режима погружения панель действий смещается вниз от своего исходного положения, примерно на то же расстояние, на которое она обычно смещается от верхней части экрана.

Я пробовал это на Nexus 4 под управлением Lollipop. Такое поведение не произошло до леденцов.

Скриншоты до, погружение, после.

Просто ActionBarActivity что иллюстрирует эту проблему:

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();
        }
    }
}

Ничего особенного в манифесте

<?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>

Тривиальный макет:

<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>

Обходной путь, который я использую в данный момент, заключается в вызове recreate() после выхода из режима погружения, но выглядит немного "глючно".

Если я до minSdkVersion и использовать Activity вместо ActionBarActivityне используйте библиотеку поддержки, тогда я не испытываю такого поведения.

Я понимаю, что режим погружения доступен только в KitKat +, и мне не нужно использовать ActionBarActivity из библиотеки поддержки, но готовый продукт должен будет работать на API версии 8+, а режим погружения является дополнительным дополнением.

Некоторые другие обходные пути, о которых я думал и отклонил пока:

  1. Есть пусковая установка Activity который сразу пересылает программно ActionBarActivity для более низких версий API.
  2. Есть несколько apks по версии API.

Любой из этих вариантов звучит как много дополнительного обслуживания.

Могу ли я попробовать что-нибудь еще? Есть ли в приведенном выше коде явные ошибки в отношении возврата из режима погружения?

Обновить

С тех пор я обновил Nexus 4 до 5.1 и библиотеку поддержки до версии 22.1.1, и поведение остается прежним. Я также обновил код, чтобы использовать новый AppCompatActivity поскольку ActionBarActivity сейчас устарела. Поведение, опять же, то же самое.

public class MainActivity extends AppCompatActivity {
    // no changes here
}

Обновить

Это странное поведение распространяется и на ландшафтный режим. В дополнение к смещению в верхней части экрана, также есть смещение в правой части экрана между концом панели действий и навигационными кнопками. Интересно, что это смещение снова кажется размером навигационной кнопки "панель", то есть больше, чем смещение вверху.

Пейзажные скриншоты до погружения, после.

2 ответа

Была такая же проблема, исправленная с помощью этого: ваш leaveImmersiveMode() Функция должна использовать эти флаги вместо:

getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                | View.SYSTEM_UI_FLAG_FULLSCREEN);

Несмотря на то, что ActionBarActivity устарел в библиотеке поддержки версии V26, изменение вашего leaveImmersiveMode() Метод для указания следующих флагов устраняет для меня проблему с тестовым приложением, использующим ваш код (который изначально показал дополнительный пробел, о котором вы упомянули).

@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_LAYOUT_STABLE
                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
        immersed = false;
//          recreate();
    }
}

Это флаги, рекомендованные в документации Android для иммерсивного режима.

Использовать панель инструментов... У меня была та же проблема, и переключение на панель инструментов вместо customContentView решило ее.

    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

И установите тему вашей деятельности на @style/Theme.AppCompat.NoActionBar

Другие вопросы по тегам