自定义Android视频播放器 - 切换横竖屏

前一篇自定义了SurfaceView,然后尝试横屏显示,虽然视频适配方面没有问题,但是没有占满整个屏幕。

我分析了一下一般的视频播放器,发现:

  • 竖屏播放视频,播放器的宽度占满手机屏幕的宽度,播放器的高度根据视频大小决定,有可能超过屏幕的高度。

  • 横屏播放视频,播放器的高度占满手机屏幕的宽度,播放器的宽度根据视频大小决定,有可能超过屏幕的高度。

根据以上两点,对自定义SurfaceView测量方法做了修改:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    // 如果videoWidth或videoHeight为0 不用做调整
    if (videoWidth <= 0 || videoHeight <= 0) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        return;
    }
    int width = 0;
    int height = 0;
    // 分情况设置View的大小
    // 观看方式:竖屏观看和横屏观看
    if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
        // 竖屏观看
        width = screenWidth;
        height = width * videoHeight / videoWidth;
        // View的高度可能超过屏幕的高度 需要做处理
    } else if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
        // 横屏观看
        height = screenWidth;
        width = height * videoWidth / videoHeight;
        // View的宽度可能超过屏幕的高度 需要做处理
    }
    // 设置大小
    setMeasuredDimension(width, height);
}

当竖屏看高屏视频(视频的高度>视频的宽度)时,或者横屏看宽屏视频(视频的高度<视频的宽度)时,按照视频的比例可能会导致超过屏幕的宽或者高,所以我们要做一些处理。

处理的方式有3种:

  • 做适屏处理。(竖屏)如果View的高度超过屏幕的高度,那么把View的高度设为屏幕的高度,然后按照视频尺寸的比例,缩小View的宽度;(横屏)如果View的宽度超过屏幕的高度,那么把View的宽度设为屏幕的高度,然后按照视频尺寸的比例,缩小View的高度。

  • 做全屏处理。(竖屏)如果View的高度超过屏幕的高度,那么把View的高度设为屏幕的高度,但是View的宽度不做任何处理,可能会导致观看的视频变形。(横屏)如果View的宽度超过屏幕的高度,那么把View的宽度设为屏幕的高度,但是View的高度不做任何处理,也可能会导致观看的视频变形。

  • 做全屏处理,但是和上面的情况不一样。无论View的高度还是宽度超过屏幕的高度,都不做任何处理,相当于多余的部分就不显示了,就是所谓的裁剪。

根据以上3种处理方式,对自定义SurfaceView测量方法再次改进:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    // 如果videoWidth或videoHeight为0 不用做调整
    if (videoWidth <= 0 || videoHeight <= 0) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        return;
    }
    int width = 0;
    int height = 0;
    // 分情况设置View的大小
    // 观看方式:竖屏观看和横屏观看
    if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
        // 竖屏观看
        width = screenWidth;
        height = width * videoHeight / videoWidth;
        // 竖屏观看竖屏视频(videoWidth < videoHeight)才需要做调整
        if (videoWidth < videoHeight) {
            switch (mode) {
                case MODE_WRAP_CONTENT :
                    // 高度超过屏幕的高度 高度等于屏幕高度 宽度减少 比例保持视频比例
                    if (height > screenHeight) {
                        height = screenHeight;
                        width = height * videoWidth / videoHeight;
                    }
                    break;
                case MODE_FILL_PARENT :
                    // 高度超过屏幕的高度 高度等于屏幕高度 宽度不减少 可能会导致变形
                    if (height > screenHeight) {
                        height = screenHeight;
                    }
                    break;
                case MODE_FIT_PARENT :
                    // 无论高度是否超过屏幕的高度 不做任何处理 超过的会被裁剪
                default :
                    break;
            }
        }
    } else if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
        // 横屏观看
        height = screenWidth;
        width = height * videoWidth / videoHeight;
        // 横屏观看横屏视频(videoWidth > videoHeight)才需要做调整
        if (videoWidth > videoHeight) {
            switch (mode) {
                case MODE_WRAP_CONTENT :
                    // 宽度超过屏幕的高度 宽度等于屏幕高度 高度减少 比例保持视频比例
                    if (width > screenHeight) {
                        width = screenHeight;
                        height = width * videoHeight / videoWidth;
                    }
                    break;
                case MODE_FILL_PARENT :
                    // 宽度超过屏幕的高度 宽度等于屏幕高度 宽高度不减少 可能会导致变形
                    if (width > screenHeight) {
                        width = screenHeight;
                    }
                    break;
                case MODE_FIT_PARENT :
                    // 无论高度是否超过屏幕的高度 不做任何处理 超过的会被裁剪
                default :
                    break;
            }
        }
    }
    // 设置大小
    setMeasuredDimension(width, height);
}

添加一个切换横竖屏时调整大小的方法

/**
 * 调整大小
 * @param screenOrientation
 * ActivityInfo.SCREEN_ORIENTATION_PORTRAIT(竖屏)
 * ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE(横屏)
 */
public void adjustSize(int screenOrientation) {
    // 赋值
    this.screenOrientation = screenOrientation;
    // 重新设置大小
    requestLayout();
}

以上关于自定义SurfaceView的修改到这里,我们看看怎么切换横竖屏。

首先我们需要在VideoSurfaceView(自定义的SurfaceView)加一层Layout,添加切换横竖屏的按钮,放在VideoSurfaceView的上层。考虑到以后添加控制条,需要用一层Layout嵌套VideoSurfaceView。我这里用的是RelativeLayout,布局相对会比较灵活,当VideoSurfaceView适屏时,可以让VideoSurfaceView居中显示。

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

    <RelativeLayout
        android:id="@+id/video_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <com.johan.video.VideoSurfaceView
            android:id="@+id/surface_view"
            android:layout_width="match_parent"
            android:layout_height="200dp"
            android:layout_centerInParent="true"
            />
        <TextView
            android:id="@+id/screen_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_margin="15dp"
            android:padding="10dp"
            android:textSize="14sp"
            android:textColor="#ffffff"
            android:text="横屏"
            android:background="#50000000"
            />
    </RelativeLayout>

 ...

</LinearLayout>

我们在activity中切换横竖屏:

public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback, SeekBar.OnSeekBarChangeListener,
        View.OnClickListener, MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener,
        MediaPlayer.OnSeekCompleteListener, MediaPlayer.OnVideoSizeChangedListener {

    private RelativeLayout videoLayout;
    private VideoSurfaceView surfaceView;
    private TextView screenButton;

    @Override
    public void onClick(View v) {
        // 切换横竖屏
        if (getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
            // 切换为竖屏
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            // 清除全屏显示
            getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
            // 更新切换按钮
            screenButton.setText("横屏");
            // 设置surfaceView外层嵌套Layout的布局参数 高度改为WRAP_CONTENT
            ViewGroup.LayoutParams layoutParams = videoLayout.getLayoutParams();
            layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
            videoLayout.setLayoutParams(layoutParams);
            // 更新surfaceView大小
            surfaceView.adjustSize(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        } else {
            // 切换为横屏
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
            // 全屏显示
            getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
            // 更新切换按钮
            screenButton.setText("竖屏");
            // // 设置surfaceView外层嵌套Layout的布局参数 高度改为MATCH_PARENT 占满整个屏幕
            ViewGroup.LayoutParams layoutParams = videoLayout.getLayoutParams();
            layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
            videoLayout.setLayoutParams(layoutParams);
            // 更新surfaceView大小
            surfaceView.adjustSize(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        }
    }

}

由于我们切换了屏幕的方向,如果我们不做任何相关处理的话,onCreate会重新调用,所以我们需要在AndroidManifest.xml中,在对应的Activity加入android:configChanges=”keyboardHidden|orientation|screenSize”属性。这点一定要注意!!

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.johan.study">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity"
            android:configChanges="keyboardHidden|orientation|screenSize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

如果有需要的话,可以重写Activity的onConfigurationChanged方法

public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback, SeekBar.OnSeekBarChangeListener,
        View.OnClickListener, MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener,
        MediaPlayer.OnSeekCompleteListener, MediaPlayer.OnVideoSizeChangedListener {

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

}

关于切换横竖屏到这里就结束了,可能以后还会做修改!!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值