横竖屏切换SurfaceView 大小的调整

news/2024/11/28 9:36:50/

视频播放的实现大概有以下形式:

1.使用系统自带视频播放类VideoView

2.使用MediaPlayer+surfaceView

3.使用一些第三方框架如:vitamio 还有像新浪在github上开放的视频播放框架等...

使用场景:

第一种方法:简单,但是VideoView不支持自定义视频,也就是你只能使用系统给你提供的布局,这在很大时候是不符合我们项目需求的。

第二种方法:使用MediaPlayer+surfaceView的话支持我们自定义布局,使用起来稍微复杂,这种方法存在的一个缺点就是只是支持MP4 3gp这样的视频编码格式,其他格式的视频均不能播放。

第三种方法:使用第三方框架,不用多说,照着SDK来就行了,相对也简单,同时支持更多的播放格式,再是目前这样的框架好像收费的居多。


SurfaceView在横竖屏切换情况下应如何调整大小

首先先看效果图:

    


布局如下:

<?xml version="1.0" encoding="utf-8"?>
<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.sj.vediodemo.MainActivity"><RelativeLayoutandroid:id="@+id/layout_gesture"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="#000"android:gravity="center_horizontal"><SurfaceViewandroid:id="@+id/sv"android:layout_width="match_parent"android:layout_height="match_parent"/></RelativeLayout><Buttonandroid:id="@+id/change"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:layout_centerHorizontal="true"android:onClick="changeOrientation"android:text="横竖屏切换"/>
</RelativeLayout>

很简单,上面一个SurfaceView 下面一个Button 用于横竖屏切换。

在ManiFest.xml 中设置:

 <activityandroid:name=".MainActivity1"android:configChanges="keyboard|screenSize|orientation"android:label="@string/app_name"android:screenOrientation="portrait"><intent-filter><action android:name="android.intent.action.MAIN"/><category android:name="android.intent.category.LAUNCHER"/></intent-filter></activity>

设置了一个ScreenOrientation 属性为纵向,同时设置了configChanges 属性,为了防止横竖屏切换导致Activity重新创建。

Main.java 代码:

public class MainActivity1 extends AppCompatActivityimplements SurfaceHolder.Callback, MediaPlayer.OnPreparedListener {public static final float SHOW_SCALE = 16 * 1.0f / 9;private RelativeLayout mSurfaceLayout;private SurfaceView mSurfaceView;private SurfaceHolder mHolder;private MediaPlayer mMediaPlayer;//屏幕宽度private int mScreenWidth;//屏幕高度private int mScreenHeight;//记录现在的播放位置private int mCurrentPos;private boolean isLand;private DisplayMetrics displayMetrics;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main1);displayMetrics = new DisplayMetrics();this.getWindow().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);mScreenWidth = displayMetrics.widthPixels;mScreenHeight = displayMetrics.heightPixels;//后台异常终止,应当恢复原有位置播放if (savedInstanceState != null)mCurrentPos = savedInstanceState.getInt("currentPos", 0);initView();}private void initView() {mSurfaceLayout = (RelativeLayout) findViewById(R.id.layout_gesture);RelativeLayout.LayoutParams lp =(RelativeLayout.LayoutParams) mSurfaceLayout.getLayoutParams();lp.height = (int) (mScreenWidth * SHOW_SCALE);mSurfaceLayout.setLayoutParams(lp);mSurfaceView = (SurfaceView) findViewById(R.id.sv);mHolder = mSurfaceView.getHolder();mHolder.addCallback(this);}private void resetSize() {float areaWH = 0.0f;int height;if (!isLand) {// 竖屏16:9height = (int) (mScreenWidth / SHOW_SCALE);areaWH = SHOW_SCALE;} else {//横屏按照手机屏幕宽高计算比例height = mScreenHeight;areaWH = mScreenWidth / mScreenHeight;}RelativeLayout.LayoutParams layoutParams =new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, height);mSurfaceLayout.setLayoutParams(layoutParams);int mediaWidth = mMediaPlayer.getVideoWidth();int mediaHeight = mMediaPlayer.getVideoHeight();float mediaWH = mediaWidth * 1.0f / mediaHeight;RelativeLayout.LayoutParams layoutParamsSV = null;if (areaWH > mediaWH) {//直接放会矮胖int svWidth = (int) (height * mediaWH);layoutParamsSV = new RelativeLayout.LayoutParams(svWidth, height);layoutParamsSV.addRule(RelativeLayout.CENTER_IN_PARENT);mSurfaceView.setLayoutParams(layoutParamsSV);}if (areaWH < mediaWH) {//直接放会瘦高。int svHeight = (int) (mScreenWidth / mediaWH);layoutParamsSV = new RelativeLayout.LayoutParams(mScreenWidth, svHeight);layoutParamsSV.addRule(RelativeLayout.CENTER_IN_PARENT);mSurfaceView.setLayoutParams(layoutParamsSV);}}private void initMediaPlayer() {if (mMediaPlayer != null) {//从Home 返回mMediaPlayer.setDisplay(mHolder);mMediaPlayer.start();} else {mMediaPlayer = new MediaPlayer();  //销毁返回重新初始化try {mMediaPlayer.setDataSource(this, Uri.parse(MediaPath.MEDIA_HENG));mMediaPlayer.setLooping(true);mMediaPlayer.setDisplay(mHolder);mMediaPlayer.setOnPreparedListener(this);mMediaPlayer.prepareAsync();mMediaPlayer.setScreenOnWhilePlaying(true);} catch (IOException e) {e.printStackTrace();}}}//只有在点击Home键或者程序发生异常时才会执行此方法@Overrideprotected void onSaveInstanceState(Bundle outState) {outState.putInt("currentPos", mCurrentPos);super.onSaveInstanceState(outState);}@Overridepublic void surfaceCreated(SurfaceHolder holder) {//SV可见initMediaPlayer();}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {//SV状态变化}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {if (mMediaPlayer != null) {mMediaPlayer.pause();mCurrentPos = mMediaPlayer.getCurrentPosition();}}/*** 销毁掉MediaPlayer对象*/private void releaseMP() {if (mMediaPlayer != null) {mMediaPlayer.stop();mMediaPlayer.release();mMediaPlayer = null;System.gc();}}@Overridepublic void onPrepared(MediaPlayer mp) {resetSize();if (mCurrentPos != 0) {mMediaPlayer.seekTo(mCurrentPos);}mMediaPlayer.start();}@Overridepublic void onConfigurationChanged(Configuration newConfig) {super.onConfigurationChanged(newConfig);isLand = newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE;getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);mScreenWidth = displayMetrics.widthPixels;mScreenHeight = displayMetrics.heightPixels;resetSize();}public void changeOrientation(View view) {if (Configuration.ORIENTATION_LANDSCAPE == this.getResources().getConfiguration().orientation) {setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);} else {setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);}}@Overridepublic void onWindowFocusChanged(boolean hasFocus) {super.onWindowFocusChanged(hasFocus);if (hasFocus && Build.VERSION.SDK_INT >= 19) {View decorView = getWindow().getDecorView();decorView.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);}}@Overrideprotected void onDestroy() {super.onDestroy();releaseMP();}
}


因为主要是讲解SurfaceView大小的调整问题,所以并没有去定制控制MediaPlayer的UI布局,简单的分析一下代码:

先来看initView()方法:

1. 目前纵向视频播放一般接受的尺寸为16:9,所以在这我也是设置了16:9的尺寸,视频的宽(RelativeLayout的宽)为手机的宽,视频高的话,根据比例换算。


2.SurfaceView的产生和销毁,都是通过SurfaceHolder进行控制的,添加上SurfaceView的监听事件,这个的话原因想必大家也都知道,一旦Activity切换到后台或者跳转到其他的Activity界面,SurfaceView 就会被销毁,当切换回来Activity界面的时候SurfaceView 又会自动创建,这个时候我们需要重新绑定上新的SurfaceHolder,不然就会出现只是播放声音而不播放画面的问题,代码中每次执行SurfaceCreate()都会执行initMediaPlayer()这个方法,在这个方法中重新绑定了一次SurfaceHoder.

3.播放完毕或者是停止都需要将MediaPlayer资源释放掉。

Ok,主要来 分析一下resetSize()这个方法:

resetSize()这个方法,没别在onPrepare()和onConfigurationChanged中调用到了,一个是视频准备完成,另外一个是横竖屏切换。

53行:

if (!isLand) {// 竖屏16:9height = (int) (mScreenWidth / SHOW_SCALE);areaWH = SHOW_SCALE;
} else {//横屏按照手机屏幕宽高计算比例height = mScreenHeight;areaWH = mScreenWidth / mScreenHeight;
}


isLand 是否横屏,不是的话根据16:9比例计算出视频框高,是横屏的话,则手机屏幕的高作为视频框的高,比例当然是视频的宽/高,需要注意的是手机横竖屏切换会导致屏幕的宽高颠倒,在onConfigChanged()中已重新获取了手机宽高。

 
int mediaWidth = mMediaPlayer.getVideoWidth();
int mediaHeight = mMediaPlayer.getVideoHeight();float mediaWH = mediaWidth * 1.0f / mediaHeight;


获取视频大小的宽高比

if (areaWH > mediaWH) {//直接放会矮胖int svWidth = (int) (height * mediaWH);layoutParamsSV = new RelativeLayout.LayoutParams(svWidth, height);layoutParamsSV.addRule(RelativeLayout.CENTER_IN_PARENT);mSurfaceView.setLayoutParams(layoutParamsSV);
}if (areaWH < mediaWH) {//直接放会瘦高。int svHeight = (int) (mScreenWidth / mediaWH);layoutParamsSV = new RelativeLayout.LayoutParams(mScreenWidth, svHeight);layoutParamsSV.addRule(RelativeLayout.CENTER_IN_PARENT);mSurfaceView.setLayoutParams(layoutParamsSV);
}

如果是播放区域宽高比大于视频宽高比的话,这个时候的情况就是视频的高要大一些,那么需要缩放到视频播放框以内,也就是让视频的高等于播放区的高度,
同时按照视频的宽高比进行等比例缩放即可。如果是播放区的宽高比小于视频的宽高比的话,这个时候说明视频的宽高更大一些,我们需要将播放框的宽作为视
频的宽,然后按照等比例缩放计算出视频的高度。计算出宽高之后SurfaceView重新布局即可。SurfaceView 布局在RleativeLayout中设置了居中对其.


http://www.ppmy.cn/news/676667.html

相关文章

关于SurfaceView横竖屏切换显示问题

我们一般都会用SurfaceView做预览和播放&#xff0c;话不多说&#xff0c;直接上代码清单文件中设置好代码中实现onConfigurationChanged()方法 android:configChanges"orientation|screenSize Override public void onConfigurationChanged(Configuration newConfig) {s…

三星S8原生android8.0,三星S8惧怕的全面屏机皇杀到,原生安卓8.0系统

原标题&#xff1a;三星S8惧怕的全面屏机皇杀到&#xff0c;原生安卓8.0系统 去年底的小米MIX带动了全面屏的兴起&#xff0c;而今年就是全面屏“元年”&#xff01; 先有三星旗舰机皇S8打先锋&#xff0c;后有努比亚Z17耀世登场&#xff0c;更有安卓之父的Essential Phone围追…

galaxy s8 android pc,现在 你可以用三星S8解锁Win 10 PC了

Samsung Flow是一款可在设备之间实现无缝、安全连接体验的软件。用户可以通过智能手机对平板电脑/PC进行身份验证&#xff0c;在设备之间共享内容&#xff0c;将智能手机中的通知同步到平板电脑/PC。此外&#xff0c;还可以启用智能手机的热点&#xff0c;使平板电脑/PC保持连接…

三星s8是否支持html,真正的全面屏!国行三星S8终于支持导航栏隐藏

自从三星发布了Galaxy S8之后&#xff0c;就掀起来一股热潮。我们暂且不看 外观设计和性能配置&#xff0c;光凭那超高的全面屏设计&#xff0c;就足够让用户们为之追捧。毕竟国内手机市场中的智能手机已经逐渐的趋于同质化&#xff0c;不是我像你&#xff0c;就是你像我。唯一…

如何一秒将 iPhone 屏幕变成 S8

追随了 iPhone 很多年的你们&#xff0c;偶尔有没有羡慕过别的类型的安卓机捏&#xff01;都听说了三星 Galaxy S8/S8 带来全新的“ Infinity Display ”&#xff0c;它为了给手机带来更强烈的观感&#xff0c;搞了一种“无边框、全正面、边到边”的显示屏&#xff0c;听起来是…

Windows11设置菜单栏(任务栏)位置居中或者靠左显示

前言 大家都知道Windows11最下面的任务栏是居中的&#xff0c;今天我升级了一下版本&#xff0c;重启之后发现任务栏跑左边了&#xff0c;我这种强迫症者直接破防。今天怎么说也得把它整回去。 当然如果你觉得居中很难受&#xff0c;想靠左展示&#xff0c;那么也可以按照此文…

做一套给三星手机用的导航栏图标(伪装Windows10移动版)

三星手机可以自定义导航栏logo&#xff0c;可以设置成各种形状。之前乐max发给我一套Windows10的logo&#xff0c;后来重置手机就找不到了。今天突发奇想自己去做一套。但是我也不会用ps&#xff0c;ai&#xff0c;也不想去装adobe全家桶&#xff0c;然后我突然想到了可以用vis…

制作投票链接小程序教程,让你的活动更具吸引力与效果

相信投票链接是一种方便快捷的投票方式&#xff0c;不仅可以用于活动中的投票&#xff0c;还可以用于品牌营销和市场调研。投票链接是一种非常方便的方式来进行在线投票。这里就推荐一个免费制作投票活动的网站&#xff1a;乔拓云&#xff0c;创建简单、免费使用、操作灵活。支…