前一篇自定义了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居中显示。
<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”属性。这点一定要注意!!
<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);
}
}
关于切换横竖屏到这里就结束了,可能以后还会做修改!!