Android VideoView изменение ориентации с буферизованным видео - PullRequest
50 голосов
/ 14 декабря 2010

Я пытаюсь повторить функциональность последнего приложения YouTube на Android Marketplace. При просмотре видео есть две отдельные компоновки: одна в портретной ориентации, которая предоставляет дополнительную информацию, и другая в альбомной ориентации, которая обеспечивает полноэкранный просмотр видео.

YouTube app portrait layout
Приложение YouTupe в портретном режиме

YouTube app landscape layout
Приложение YouTube в ландшафтном режиме

(Извините за случайность фотографий, но они были первыми фотографиями, которые я смог найти в реальном макете)

Это довольно легко сделать обычно - просто укажите альтернативный макет в layout-land, и все будет хорошо. Дело в том, что приложение YouTube действительно хорошо работает (и я пытаюсь его воспроизвести), что при изменении ориентации видео продолжает воспроизводиться и не требует повторной буферизации с самого начала.

Я выяснил, что переопределение onConfigurationChange () и установка новых LayoutParameters позволит мне изменить размер видео без принудительного создания буферов - однако видео будет случайным образом масштабироваться до различной ширины / высоты при повороте экрана несколько раз. Я пытался делать всевозможные вызовы invalidate () в VideoView, пытался вызвать RequestLayout () в родительском контейнере RelativeLayout и просто пробовал как можно больше разных вещей, но я не могу заставить его работать должным образом. Любой совет будет принята с благодарностью!

Вот мой код:

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        questionText.setVisibility(View.GONE);
        respond.setVisibility(View.GONE);
        questionVideo.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
    } else {
        questionText.setVisibility(View.VISIBLE);
        respond.setVisibility(View.VISIBLE);
        Resources r = getResources();
        int height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 150.0f, r.getDisplayMetrics());
        questionVideo.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT, height));
    }
}

РЕДАКТИРОВАТЬ: я обнаружил в logcat какой-то интересный вывод, который появляется, когда мое видео вращается, что кажется виновником - хотя я понятия не имею, как это исправить:

Выход Logcat при правильном изменении размера (занимает все окно)

обратите внимание на h = 726

12-13 15:37:35.468  1262  1270 I ActivityManager: Config changed: { scale=1.0 imsi=310/4 loc=en_US touch=3 keys=1/1/2 nav=1/1 orien=2 layout=34 uiMode=17 seq=210}
12-13 15:37:35.561  1262  1268 I TIOverlay: Position/X0/Y76/W480/H225
12-13 15:37:35.561  1262  1268 I TIOverlay: Adjusted Position/X1/Y0/W403/H225
12-13 15:37:35.561  1262  1268 I TIOverlay: Rotation/90
12-13 15:37:35.561  1262  1268 I Overlay : v4l2_overlay_set_position:: w=480 h=224
12-13 15:37:35.561  1262  1268 I Overlay : v4l2_overlay_set_position:: w=402 h=726
12-13 15:37:35.561  1262  1268 I Overlay : dumping driver state:
12-13 15:37:35.561  1262  1268 I Overlay : output pixfmt:
12-13 15:37:35.561  1262  1268 I Overlay : w: 432
12-13 15:37:35.561  1262  1268 I Overlay : h: 240
12-13 15:37:35.561  1262  1268 I Overlay : color: 7
12-13 15:37:35.561  1262  1268 I Overlay : UYVY
12-13 15:37:35.561  1262  1268 I Overlay : v4l2_overlay window:
12-13 15:37:35.561  1262  1268 I Overlay : window l: 1 
12-13 15:37:35.561  1262  1268 I Overlay : window t: 0 
12-13 15:37:35.561  1262  1268 I Overlay : window w: 402 
12-13 15:37:35.561  1262  1268 I Overlay : window h: 726

Выход Logcat при неправильном изменении размера (занимает крошечную часть полного экрана)

обратите внимание на h = 480

12-13 15:43:00.085  1262  1270 I ActivityManager: Config changed: { scale=1.0 imsi=310/4 loc=en_US touch=3 keys=1/1/2 nav=1/1 orien=2 layout=34 uiMode=17 seq=216}
12-13 15:43:00.171  1262  1268 I TIOverlay: Position/X0/Y76/W480/H225
12-13 15:43:00.171  1262  1268 I TIOverlay: Adjusted Position/X138/Y0/W266/H225
12-13 15:43:00.171  1262  1268 I TIOverlay: Rotation/90
12-13 15:43:00.179  1262  1268 I Overlay : v4l2_overlay_set_position:: w=480 h=224
12-13 15:43:00.179  1262  1268 I Overlay : v4l2_overlay_set_position:: w=266 h=480
12-13 15:43:00.179  1262  1268 I Overlay : dumping driver state:
12-13 15:43:00.179  1262  1268 I Overlay : output pixfmt:
12-13 15:43:00.179  1262  1268 I Overlay : w: 432
12-13 15:43:00.179  1262  1268 I Overlay : h: 240
12-13 15:43:00.179  1262  1268 I Overlay : color: 7
12-13 15:43:00.179  1262  1268 I Overlay : UYVY
12-13 15:43:00.179  1262  1268 I Overlay : v4l2_overlay window:
12-13 15:43:00.179  1262  1268 I Overlay : window l: 138 
12-13 15:43:00.179  1262  1268 I Overlay : window t: 0 
12-13 15:43:00.179  1262  1268 I Overlay : window w: 266 
12-13 15:43:00.179  1262  1268 I Overlay : window h: 480

Может быть, кто-то знает, что такое «Наложение» и почему он не получает правильное значение высоты?

Ответы [ 11 ]

57 голосов
/ 15 декабря 2010

РЕДАКТИРОВАТЬ: (июнь 2016 г.)

Этот ответ очень старый (я думаю, Android 2.2 / 2.3) и, вероятно, не так актуален, как другие ответы ниже! Сначала посмотрите на них, если вы не разрабатываете устаревшую версию Android:)


Мне удалось сузить проблему до функции onMeasure в классе VideoView. Создав дочерний класс и переопределив функцию onMeasure, я смог получить желаемую функциональность.

public class VideoViewCustom extends VideoView {

    private int mForceHeight = 0;
    private int mForceWidth = 0;
    public VideoViewCustom(Context context) {
        super(context);
    }

    public VideoViewCustom(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public VideoViewCustom(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public void setDimensions(int w, int h) {
        this.mForceHeight = h;
        this.mForceWidth = w;

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        Log.i("@@@@", "onMeasure");

        setMeasuredDimension(mForceWidth, mForceHeight);
    }
}

Тогда внутри своей Деятельности я просто сделал следующее:

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

        questionVideo.setDimensions(displayHeight, displayWidth);
        questionVideo.getHolder().setFixedSize(displayHeight, displayWidth);

    } else {
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN, WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);

        questionVideo.setDimensions(displayWidth, smallHeight);
        questionVideo.getHolder().setFixedSize(displayWidth, smallHeight);

    }
}

Строка:

questionVideo.getHolder().setFixedSize(displayWidth, smallHeight);

является ключевым для того, чтобы сделать эту работу. Если вы выполните вызов setDimensions без этого парня, размер видео все равно не изменится.

Единственное, что вам нужно сделать, это убедиться, что вы вызываете setDimensions () внутри метода onCreate (), иначе ваше видео не начнет буферизоваться, так как видео не будет настроено для рисования на поверхности любого размера. .

// onCreate()
questionVideo.setDimensions(initialWidth, initialHeight); 

Одна последняя клавиша деталь - если вам когда-нибудь станет интересно, почему VideoView не изменяет размеры при вращении, вам нужно убедиться, что размеры, к которым вы изменяете размер, равны точно равно видимой области или меньше ее. У меня была действительно большая проблема, когда я устанавливал ширину / высоту VideoView на весь размер дисплея, когда у меня все еще были панель уведомлений / строка заголовка на экране, и это не меняло размеры VideoView вообще. Простое удаление панели уведомлений и строки заголовка устранило проблему.

Надеюсь, это поможет кому-то в будущем!

23 голосов
/ 01 января 2013

Вот действительно простой способ выполнить то, что вы хотите, с минимальным кодом:

AndroidManifest.xml:

android:configChanges="orientation|keyboard|keyboardHidden|screenSize|screenLayout|uiMode"

Примечание: отредактируйте, как требуется для вашего API, это охватывает 10+, но для более низких API необходимо удалить часть этой строки «screenSize | screenLayout | uiMode»

Внутри метода «OnCreate», обычно в разделе «super.onCreate», добавьте:

getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FULLSCREEN);

И затем где-нибудь, обычно внизу, добавьте:

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FULLSCREEN);
}

Это позволит изменить размер видео на полный экран всякий раз, когда ориентация изменилась без прерывания воспроизведения, и требует только переопределения метода конфигурации.

23 голосов
/ 02 ноября 2011

Прежде всего, большое спасибо за ваш обширный ответ.

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

Я попробовал ваше решение, но я также попробовал случайные вещи, и случайно заметил, что, если мой VideoView центрирован на его родительском объекте, он волшебным образом работает сам по себе (никакой пользовательский VideoView не требуется или что-либо еще).

Если быть более точным, то с помощью этого макета большую часть времени я воспроизвожу проблему:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <VideoView
        android:id="@+id/videoView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>

С этим одним макетом у меня никогда не возникает проблем (плюс, видео центрировано, как и должно быть;):

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <VideoView
        android:id="@+id/videoView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerInParent="true" />

</RelativeLayout>

Он также работает с wrap_content вместо match_parent (видео по-прежнему занимает все пространство), что для меня не имеет большого смысла.

В любом случае, у меня нет никакого объяснения этому - для меня это похоже на ошибку VideoView.

11 голосов
/ 28 февраля 2014

VideoView использует так называемый оверлей, который представляет собой область, в которой отображается видео. Это наложение находится за окном, удерживающим VideoView. VideoView пробивает отверстие в своем окне, чтобы наложение было видимым. Затем он синхронизируется с макетом (например, при перемещении или изменении размера VideoView наложение также должно быть перемещено и изменено в размере).

На этапе макета где-то есть ошибка, из-за которой наложение использует предыдущий размер, установленный VideoView.

Чтобы исправить это, создайте подкласс VideoView и переопределите onLayout:

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    super.onLayout(changed, left, top, right, bottom);
    getHolder().setSizeFromLayout();
}

и размер наложения будет соответствовать размеру макета VideoView.

7 голосов
/ 10 декабря 2013

Репликация приложения YouTube

Мне удалось создать пример проекта, для которого не требуется android:configChanges="orientation" или пользовательский VideoView. Получающийся опыт идентичен тому, как приложение YouTube обрабатывает вращение во время воспроизведения видео. Другими словами, видео не нужно приостанавливать, повторно буферизовать или перезагружать, и оно не пропускает и не пропускает какие-либо аудиокадры при изменении ориентации устройства.

Оптимальный метод

Этот метод использует TextureView и сопровождающий его SurfaceTexture в качестве приемника для текущего видеокадра MediaPlayer. Поскольку SurfaceTexture использует объект текстуры GL (на который просто ссылается целое число из контекста GL), верьте, что можно сохранить ссылку на SurfaceTexture посредством изменений конфигурации. Сам текстурный вид уничтожается и воссоздается во время изменения конфигурации (вместе с задним действием), а вновь созданный текстурный вид просто обновляется со ссылкой на SurfaceTexture перед его присоединением.

Я создал полный рабочий пример , показывающий, как и когда инициализировать ваш MediaPlayer и возможный MediaController, и я выделю интересные части, относящиеся к этому вопросу, ниже:

public class VideoFragment {

    TextureView mDisplay;
    SurfaceTexture mTexture;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        final View rootView = inflater.inflate(R.layout.fragment_main, container, false);
        mDisplay = (TextureView) rootView.findViewById(R.id.texture_view);
        if (mTexture != null) {
            mDisplay.setSurfaceTexture(mTexture);
        }
        mDisplay.setSurfaceTextureListener(mTextureListener);

        return rootView;
    }

    TextureView.SurfaceTextureListener mTextureListener = new TextureView.SurfaceTextureListener() {
        @Override
        public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
            mTexture = surface;
            // Initialize your media now or flag that the SurfaceTexture is available..
        }

        @Override
        public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
            mTexture = surface;
        }

        @Override
        public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
            mTexture = surface;
            return false; // this says you are still using the SurfaceTexture..
        }

        @Override
        public void onSurfaceTextureUpdated(SurfaceTexture surface) {
            mTexture = surface;
        }
    };

    @Override
    public void onDestroyView() {
        mDisplay = null;
        super.onDestroyView();
    }

    // ...

}

Поскольку в решении используется сохраненный фрагмент, а не операция, которая обрабатывает изменения конфигурации вручную, вы можете полностью использовать систему инфляции ресурсов для конкретной конфигурации, как это было бы естественно. К сожалению, если ваш минимальный sdk ниже API 16, вам, по сути, потребуется сделать бэкпорт TextureView (чего я не сделал).

Наконец, если вам интересно, проверьте мой первоначальный вопрос подробно: мой оригинальный подход, стек мультимедиа Android, почему он не работает и альтернативный обходной путь.

3 голосов
/ 28 октября 2013

используйте это:

@Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);

        if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {

            getActivity().getWindow().addFlags(
                    WindowManager.LayoutParams.FLAG_FULLSCREEN);
            getActivity().getWindow().clearFlags(
                    WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);

        } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {

            getActivity().getWindow().addFlags(
                    WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
            getActivity().getWindow().clearFlags(
                    WindowManager.LayoutParams.FLAG_FULLSCREEN);

        }
    }

Также не забудьте добавить строку ниже к вашей деятельности в манифесте:

android:configChanges="orientation|keyboard|keyboardHidden|screenSize"
2 голосов
/ 26 июня 2015

см. Мой пример кода, он работает для меня

public class CustomVideoView extends android.widget.VideoView {
private int width;
private int height;
private Context context;
private VideoSizeChangeListener listener;
private boolean isFullscreen;

public CustomVideoView(Context context) {
    super(context);
    init(context);
}

public CustomVideoView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context);
}

/**
 * get video screen width and height for calculate size
 *
 * @param context Context
 */
private void init(Context context) {
    this.context = context;
    setScreenSize();
}

/**
 * calculate real screen size
 */
private void setScreenSize() {
    Display display = ((Activity) context).getWindowManager().getDefaultDisplay();

    if (Build.VERSION.SDK_INT >= 17) {
        //new pleasant way to get real metrics
        DisplayMetrics realMetrics = new DisplayMetrics();
        display.getRealMetrics(realMetrics);
        width = realMetrics.widthPixels;
        height = realMetrics.heightPixels;

    } else if (Build.VERSION.SDK_INT >= 14) {
        //reflection for this weird in-between time
        try {
            Method mGetRawH = Display.class.getMethod("getRawHeight");
            Method mGetRawW = Display.class.getMethod("getRawWidth");
            width = (Integer) mGetRawW.invoke(display);
            height = (Integer) mGetRawH.invoke(display);
        } catch (Exception e) {
            //this may not be 100% accurate, but it's all we've got
            width = display.getWidth();
            height = display.getHeight();
        }

    } else {
        //This should be close, as lower API devices should not have window navigation bars
        width = display.getWidth();
        height = display.getHeight();
    }

    // when landscape w > h, swap it
    if (width > height) {
        int temp = width;
        width = height;
        height = temp;
    }
}

/**
 * set video size change listener
 *
 */
public void setVideoSizeChangeListener(VideoSizeChangeListener listener) {
    this.listener = listener;
}

public interface VideoSizeChangeListener {
    /**
     * when landscape
     */
    void onFullScreen();

    /**
     * when portrait
     */
    void onNormalSize();
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    if (context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
        // full screen when landscape
        setSize(height, width);
        if (listener != null) listener.onFullScreen();
        isFullscreen = true;
    } else {
        // height = width * 9/16
        setSize(width, width * 9 / 16);
        if (listener != null) listener.onNormalSize();
        isFullscreen = false;
    }
}

/**
 * @return true: fullscreen
 */
public boolean isFullscreen() {
    return isFullscreen;
}

/**
 * set video sie
 *
 * @param w Width
 * @param h Height
 */
private void setSize(int w, int h) {
    setMeasuredDimension(w, h);
    getHolder().setFixedSize(w, h);
}
}

и не создавать заново вид при изменении ориентации

// AndroidManifest.xml
android:configChanges="screenSize|orientation|keyboardHidden"

portrain

пейзаж landscape

мой исходный код здесь

2 голосов
/ 08 апреля 2015

Я взял примеры из некоторых ответов здесь и попытался сделать это по-своему.Выглядит как простое решение.

videoLayout = (RelativeLayout) videoView.findViewById(R.id.videoFrame);

onConfigurationChange внутри фрагмента. Где видео отображается в полноэкранном режиме в альбомном режиме.мой файл макета

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

<RelativeLayout 
    android:id="@+id/videoFrame"
    android:layout_height="200dp"
    android:layout_width="match_parent">

    <VideoView
        android:id="@+id/video"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerHorizontal="true"/>

</RelativeLayout>

У меня есть другой относительный макет ниже этого, которого нет в этом макете.Но это не имеет никакого значения.

1 голос
/ 09 апреля 2014

Хотя Mark37 (очень полезно) ответ действительно работает, для этого необходимо установить размеры вручную (используя setDimensions).Это может быть хорошо в приложении, где желаемые размеры известны заранее, но если вы хотите, чтобы виды автоматически определяли размер на основе параметров видео (например, чтобы убедиться, что сохраняется исходное соотношение сторон), необходим другой подход.

К счастью, оказывается, что часть setDimensions на самом деле не нужна. onMeasure VideoView уже включает в себя всю необходимую логику, поэтому вместо того, чтобы полагаться на кого-то для вызова setDimensions, можно просто вызвать super.onMeasure, а затем использовать представление getMeasuredWidth / getMeasuredHeight для получения фиксированного размера.*

Итак, класс VideoViewCustom становится простым:

public class VideoViewCustom extends VideoView {

    public VideoViewCustom(Context context) {
        super(context);
    }

    public VideoViewCustom(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public VideoViewCustom(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        getHolder().setFixedSize(getMeasuredWidth(), getMeasuredHeight());
    }
}

Эта версия не требует никакого дополнительного кода в вызывающей программе и использует все преимущества существующей реализации VideoView onMeasure.

Это на самом деле довольно похоже на подход , предложенный Zapek, который делает в основном то же самое, только с onLayout вместо onMeasure.

0 голосов
/ 27 июля 2018

ПРОСТОЙ ответ и до 2018 года.

Положительные оценки за этот ответ: Код ниже

1) Неважно, если вы установите FULL_SCREENили нет.Поскольку это соответствует родителю, это всегда будет работать.В старом принятом ответе, если вы не установили FULL_SCREEN, android возьмет на себя весь размер телефона, и тогда VideoView будет вне экрана;

2) Вам не нужно создавать Custom VideoView или PlayerView.;

3) Он не вызывает метод несколько раз.В старом принятом ответе он вызывает метод измерения несколько раз излишне;

4) Также имеется кнопка для изменения ориентации, например, приложение YouTube;

5) Установка автоматического поворота телефона в положение OFF также блокирует изменение ориентации приложения.

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    ...
    setPlayerViewLayoutParams();
    ...
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        setPlayerViewLayoutParamsForLandScape();
    } else {
        setPlayerViewLayoutParamsForPortrait();
    }
}

private void setPlayerViewLayoutParamsForLandScape() {
    ConstraintLayout.LayoutParams lp = new ConstraintLayout.LayoutParams(
            ConstraintLayout.LayoutParams.MATCH_PARENT, ConstraintLayout.LayoutParams.MATCH_PARENT);
    mPlayerView.setLayoutParams(lp);
}

private void setPlayerViewLayoutParamsForPortrait() {
    Display display = myContext.getWindowManager().getDefaultDisplay();
    Point size = new Point();
    display.getSize(size);
    int width = size.x;
    Double doubleHeight = width / 1.5;
    Integer height = doubleHeight.intValue();

    ConstraintLayout.LayoutParams lp = new ConstraintLayout.LayoutParams(
            ConstraintLayout.LayoutParams.MATCH_PARENT, height);
    mPlayerView.setLayoutParams(lp);
}

private void setPlayerViewLayoutParams() {
    if (myContext.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
        setPlayerViewLayoutParamsForLandScape();
    } else {
        setPlayerViewLayoutParamsForPortrait();
    }
}

OBS: я использую PlayerView внутри ConstraintLayout.Потому что я работаю с ExoPlayer Media Library .

frag_player.xml

<android.support.constraint.ConstraintLayout   
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">

<com.google.android.exoplayer2.ui.PlayerView
    android:id="@+id/player_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorBlack"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintVertical_bias="0.0"/>

</android.support.constraint.ConstraintLayout>

ДОПОЛНИТЕЛЬНО

Я также хочу, чтобы кнопка изменила ориентацию

Чтобы полностью воспроизвести приложение youtube, вам, вероятно, понадобится кнопка, чтобы настроить плеер на альбомную или книжную ориентацию, это полезно, если пользовательпри автоматическом отключении телефона .

Сначала вам нужно будет выполнить следующие шаги:

  1. Создать кнопку, которая изменит ориентацию;
  2. Когда пользователь нажимает кнопку, проверьте текущую ориентацию;
  3. Установите противоположную ориентацию, например, если она является текущей в LandScape, установите Портрет.

PlayerFragment.java

@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.image_button_full_screen:
            if (myContext.getResources().getConfiguration().orientation 
                == Configuration.ORIENTATION_LANDSCAPE) {
                myContext.setRequestedOrientation(
                        ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
            } else {
                myContext.setRequestedOrientation(
                        ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
            }
            break;
    }
}

ПРОБЛЕМА 1: вращение устройства больше не работает

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

ПРОБЛЕМА 2: Автоповорот телефона выключен, и он все еще меняет ориентацию

Внутри метода ниже вам необходимо проверить, еслиАвтоповорот телефона включен или выключен, если он включен, вы можете установить ОРИЕНТАЦИЮ на ДАТЧИК, чтобы телефон мог менять ориентацию, когда пользователь поворачивает устройство.В случае, если автоповорот выключен, вы ничего не делаете, поэтому ориентация будет портретной или портретной, в зависимости от того, нажал ли пользователь кнопку полноэкранного режима или нет.

private void setOrientationListener() {
    OrientationEventListener orientationEventListener = new OrientationEventListener(this) {
        @Override
        public void onOrientationChanged(int orientation) {
            // 94 > 90 - 10 and 94 < 90 + 10     //   80 < orientation < 100.  Rotating to the LEFT.
            // 278 > 270 - 10 and 278 < 270 + 10 //   260 < orientation < 280. Rotating to the RIGHT.
            int epsilon = 10;
            int leftLandscape = 90;
            int rightLandscape = 270;
            if (epsilonCheck(orientation, leftLandscape, epsilon) ||
                    epsilonCheck(orientation, rightLandscape, epsilon)) {
                if (android.provider.Settings.System.getInt(getContentResolver(),
                        Settings.System.ACCELEROMETER_ROTATION, 0) == 1) {
                    // Phone's auto rotation is ON
                    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
                }
            }
        }

        private boolean epsilonCheck(int a, int b, int epsilon) {
            return a > b - epsilon && a < b + epsilon;
        }
    };
    orientationEventListener.enable();
}

Если вы работаете с мультимедийным приложением, у меня есть образец , который научит вас, как эффективно использовать библиотеку Exoplayer.

...