Android: настройка MediaController для соответствия системному интерфейсу не работает с панелью действий

У меня есть активность, которая показывает видео с использованием VideoView с пользовательским MediaController. Системный интерфейс скрыт до тех пор, пока пользователь не коснется экрана, чтобы отобразить MediaController (как в приложении YouTube или Фото).

Следующий метод позволяет скрыть системный интерфейс:

private void hideSystemUi() {
    int flags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
                View.SYSTEM_UI_FLAG_FULLSCREEN |
                View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
        getWindow().getDecorView().setSystemUiVisibility(flags);

}

И макет деятельности:

<FrameLayout android:id="@+id/root"
             xmlns:android="http://schemas.android.com/apk/res/android"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:focusable="true"
             android:keepScreenOn="true">

    <com.google.android.exoplayer.AspectRatioFrameLayout
        android:id="@+id/video_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center">

        <SurfaceView
            android:id="@+id/surface_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="center"/>

    </com.google.android.exoplayer.AspectRatioFrameLayout>
</FrameLayout>

Затем я добавляю MediaController в video_frame с помощью кода, например, так:

mMediaController.setAnchorView(findViewById(R.id.video_frame));

Тестируя с Nexus 5, я заметил, что при отображении MediaController программная панель навигации перекрывает пользовательский интерфейс MediaController. Мне удалось это исправить, добавив следующий атрибут в корень макета MediaController:

android:fitsSystemWindows="true"

Все идет нормально. Это работало отлично, пока моя тема была Theme.AppCompat.NoActionBar, Теперь, когда я провожу рефакторинг приложения, получая его в соответствии с рекомендациями по дизайну материалов, я должен показать ActionBar. Поэтому я сменил тему на Theme.AppCompat и угадай что? Системный интерфейс еще раз перекрывает MediaController. Кажется, что android:fitsSystemWindows="true" больше не имеет никакого влияния.

Я пытался установить android:fitsSystemWindows="true" непосредственно к самой теме "Активность", и это, казалось, решило проблему с перекрытием, но потом я получил еще одну проблему, когда VideoView был дополнен совершенно странным образом со случайного направления вместо масштабирования, чтобы соответствовать экрану, как это было раньше.

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

1 ответ

Решение

Изучив шаблон Fullscreen Activity в Android Studio, я заметил, что в макете FullscreenActivity они используют android:fitsSystemWindows="true" немного по-другому, чем я.

Вот макет, который поставляется с шаблоном (activity_fullscreen.xml):

<FrameLayout 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"
             android:background="#0099cc"
             tools:context=".FullscreenActivity">

    <!-- The primary full-screen view. This can be replaced with whatever view
         is needed to present your content, e.g. VideoView, SurfaceView,
         TextureView, etc. -->
    <TextView android:id="@+id/fullscreen_content"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:keepScreenOn="true"
              android:textColor="#33b5e5"
              android:textStyle="bold"
              android:textSize="50sp"
              android:gravity="center"
              android:text="@string/dummy_content"/>

    <!-- This FrameLayout insets its children based on system windows using
         android:fitsSystemWindows. -->
    <FrameLayout android:layout_width="match_parent"
                 android:layout_height="match_parent"
                 android:fitsSystemWindows="true">

        <LinearLayout android:id="@+id/fullscreen_content_controls"
                      style="?metaButtonBarStyle"
                      android:layout_width="match_parent"
                      android:layout_height="wrap_content"
                      android:layout_gravity="bottom|center_horizontal"
                      android:background="@color/black_overlay"
                      android:orientation="horizontal"
                      tools:ignore="UselessParent">

            <Button android:id="@+id/dummy_button"
                    style="?metaButtonBarButtonStyle"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:text="@string/dummy_button"/>

        </LinearLayout>
    </FrameLayout>

</FrameLayout>

Я заметил, что у них есть дополнительный FrameLayout контейнер с android:fitsSystemWindows="true" который оборачивает фактический контейнер макета (в моем случае это был MediaController) внизу экрана.

Однажды я добавил FrameLayout обернуть мой MediaController макет, как показано в приведенном выше фрагменте кода, моя проблема исчезла! Действительно странно, что мне нужен дополнительный макет контейнера, чтобы решить эту проблему. Особенно, когда Android Studio говорит, что у меня есть "Бесполезный родитель".

Итак, подведем итог, вот полностью рабочее решение того, как выглядит мой макет Activity:

<FrameLayout android:id="@+id/root"
             xmlns:android="http://schemas.android.com/apk/res/android"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:focusable="true"
             android:keepScreenOn="true">

    <com.google.android.exoplayer.AspectRatioFrameLayout
        android:id="@+id/video_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center">

        <SurfaceView
            android:id="@+id/surface_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="center"/>

    </com.google.android.exoplayer.AspectRatioFrameLayout>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true">

        <LinearLayout         android:id="@+id/controller_frame"
                              android:layout_width="match_parent"
                      android:layout_height="wrap_content"
                      android:layout_gravity="bottom|center_horizontal"
                      android:orientation="horizontal">

        </LinearLayout>

    </FrameLayout>
</FrameLayout>

и я подключаю MediaController в controller_frame вместо video_frame как я делал ранее:

mMediaController.setAnchorView(findViewById(R.id.controller_frame));
Другие вопросы по тегам