VideoView 视频播放 示例
2016-04-25 23:40
260 查看
介绍
实现的功能: 可播放本地视频或网络视频,可控制播放或暂停 最小化时保存播放位置及播放状态,resume时恢复所有状态; 横竖屏切换时保持切换前的位置及状态 在屏幕上竖直滑动可调节屏幕亮度和音量 可改变视频显示样式(有bug) 可获取视频缩略图及视频大小
Activity
import android.app.Activity;import android.content.pm.ActivityInfo;import android.content.res.Configuration;import android.media.MediaPlayer;import android.media.MediaPlayer.OnCompletionListener;import android.media.MediaPlayer.OnErrorListener;import android.media.MediaPlayer.OnPreparedListener;import android.net.Uri;import android.os.Bundle;import android.os.Environment;import android.util.Log;import android.view.GestureDetector;import android.view.GestureDetector.OnGestureListener;import android.view.MotionEvent;import android.view.View;import android.view.View.OnClickListener;import android.view.View.OnTouchListener;import android.widget.Button;import android.widget.MediaController;import android.widget.ProgressBar;import android.widget.RelativeLayout;import android.widget.Toast;import android.widget.VideoView;public class MainActivity extends Activity implements OnCompletionListener, OnErrorListener, OnPreparedListener, OnTouchListener, OnClickListener, OnGestureListener { private Button btn_switch; private Button btn_start; private Button btn_fullscreen; private VideoView mVideoView; //在 VidioView 外层套一个容器,以在切换屏幕方向的时候对 rl_vv 进行拉伸,而内部的 mVideoView 会依据视频尺寸重新计算宽高。 //若是直接具体指定了view的宽高,则视频会被拉伸。 private RelativeLayout rl_vv; private ProgressBar progressBar; //加载进度条 private int positionWhenPause = 0;//标记当视频暂停时的播放位置 private boolean isPlayingWhenPause = false;//标记最小化或横竖屏时是否正在播放 private GestureDetector mGestureDetector;//手势识别器,用户控制屏幕亮度和音量 private Uri mVideoUri; public static final String filePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/b.rmvb";//本地路径 public static final String url = "http://7xt0mj.com1.z0.glb.clouddn.com/lianaidaren.v.640.480.mp4";//网络路径 public static final String url2 = "http://7xt0mj.com1.z0.glb.clouddn.com/xia.v.1280.720.f4v"; public static final String url3 = "http://112.253.22.157/17/z/z/y/u/zzyuasjwufnqerzvyxgkuigrkcatxr/hc.yinyuetai.com /D046015255134077DDB3ACA0D7E68D45.flv"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); progressBar = (ProgressBar) findViewById(R.id.progressBar); rl_vv = (RelativeLayout) findViewById(R.id.rl_vv); mVideoView = (VideoView) findViewById(R.id.mVideoView); btn_switch = (Button) findViewById(R.id.btn_switch); btn_start = (Button) findViewById(R.id.btn_start); btn_fullscreen = (Button) findViewById(R.id.btn_fullscreen); //设置显示控制条 mVideoView.setMediaController(new MediaController(this)); mVideoUri = Uri.parse(filePath); mVideoView.setVideoURI(mVideoUri);//mVideoView.setVideoPath(url);//这两个方法都可以用来播放网络视频或本地视频 btn_switch.setOnClickListener(this); btn_start.setOnClickListener(this); btn_fullscreen.setOnClickListener(this); mVideoView.setOnCompletionListener(this); mVideoView.setOnErrorListener(this); mVideoView.setOnPreparedListener(this); mVideoView.setOnTouchListener(this); mVideoView.setOnClickListener(this); mGestureDetector = new GestureDetector(this, this); } @Override protected void onResume() { super.onResume(); //如果有保存位置,则跳转到暂停时所保存的那个位置 if (positionWhenPause > 0) { mVideoView.seekTo(positionWhenPause); //如果暂停前正在播放,则继续播放,并将播放位置置为0 if (isPlayingWhenPause) { mVideoView.start(); mVideoView.requestFocus(); positionWhenPause = 0; } } } @Override protected void onPause() { //如果当前页面暂定,则保存当前播放位置,并记录之前mVideoView是否正在播放 isPlayingWhenPause = mVideoView.isPlaying(); positionWhenPause = mVideoView.getCurrentPosition(); //停止回放视频文件,先获取再stopPlayback() mVideoView.stopPlayback(); super.onPause(); } @Override protected void onDestroy() { super.onDestroy(); if (null != mVideoView) mVideoView = null; } @Override //横竖屏切换时更改mVideoView的大小 public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); if (mVideoView == null) { return; } if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {//横屏 VideoUtils.setActivityFullScreenMode(this);//设置为全屏模式 getWindow().getDecorView().invalidate(); //rl_vv.getLayoutParams().width = VideoUtils.getScreenWidth(this); rl_vv.getLayoutParams().height = VideoUtils.getScreenHeight(this); } else {//竖屏 VideoUtils.setActivityWindowScreenMode(this); rl_vv.getLayoutParams().width = VideoUtils.getScreenWidth(this); //rl_vv.getLayoutParams().height = VideoUtils.dp2px(this, 400); } } //*************************************************************************************************************************** @Override public void onPrepared(MediaPlayer mp) { try { long timeLong = Long.valueOf(VideoUtils.getVideoLength(mVideoUri.toString())); Toast.makeText(this, "准备好了,时长为 " + VideoUtils.long2Time(timeLong), Toast.LENGTH_SHORT).show(); } catch (Exception e) { } //如果文件加载成功,隐藏加载进度条 progressBar.setVisibility(View.GONE); } @Override public void onCompletion(MediaPlayer mp) { } @Override //视频播放发生错误时回调。如果未指定回调, 或回调函数返回false,mVideoView 会通知用户发生了错误。 public boolean onError(MediaPlayer mp, int what, int extra) { switch (what) { case MediaPlayer.MEDIA_ERROR_UNKNOWN: Log.e("text", "发生未知错误"); break; case MediaPlayer.MEDIA_ERROR_SERVER_DIED: Log.e("text", "媒体服务器死机"); break; default: Log.e("text", "onError+" + what); break; } switch (extra) { case MediaPlayer.MEDIA_ERROR_IO: Log.e("text", "文件或网络相关的IO操作错误"); break; case MediaPlayer.MEDIA_ERROR_MALFORMED: Log.e("text", "比特流编码标准或文件不符合相关规范"); break; case MediaPlayer.MEDIA_ERROR_TIMED_OUT: Log.e("text", "操作超时"); break; case MediaPlayer.MEDIA_ERROR_UNSUPPORTED: Log.e("text", "比特流编码标准或文件符合相关规范,但媒体框架不支持该功能"); break; default: Log.e("text", "onError+" + extra); break; } return true;//经常会碰到视频编码格式不支持的情况,若不想弹出提示框就返回true } //************************************************************************************************************************************ @Override public boolean onTouch(View v, MotionEvent event) { return mGestureDetector.onTouchEvent(event);//把Touch事件传递给手势识别器,这一步非常重要! } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_start: if (mVideoView.isPlaying()) { mVideoView.pause(); } else { mVideoView.start();//启动视频播放 mVideoView.requestFocus();//获取焦点 } break; case R.id.btn_switch: //横竖屏切换 if (getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } else { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); } // btn_switch.setVisibility(View.INVISIBLE); break; case R.id.btn_fullscreen: VideoUtils.setVideoViewLayoutParams(this, mVideoView, VideoUtils.FULL_SCREEN); break; } } //************************************************************************************************************************************ @Override //e1代表触摸时的事件,是不变的,e2代表滑动过程中的事件,是时刻变化的 //distance是当前event2与上次回调时的event2之间的距离,代表上次回调之后到这次回调之前移动的距离 public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { float FLING_MIN_BRIGHTNESS = 1.0f * VideoUtils.dp2px(MainActivity.this, 1f);//调节亮度时的敏感度, float FLING_MIN_VOICE = 1.0f * VideoUtils.dp2px(MainActivity.this, 5f);//调节声音时的敏感度 float distance = Math.abs(distanceY);//竖直方向移动范围 //在屏幕左侧滑动调节亮度,在屏幕右侧滑动调节声音 if (e1.getX() < VideoUtils.getScreenWidth(this) / 2) {//左侧 if (distance > FLING_MIN_BRIGHTNESS) {//移动范围满足 if (e1.getY() - e2.getY() > 0) {//上滑 VideoUtils.setScreenBrightness(this, 15);//亮度增加,第二参数的大小代表着敏感度 } else {//下滑 VideoUtils.setScreenBrightness(this, -15); } } } else {//右侧 if (distance > FLING_MIN_VOICE) {//移动范围满足 if (e1.getY() - e2.getY() > 0) {//上滑 //VideoUtils.setVoiceVolume(this, 1);//音量增加 VideoUtils.setVoiceVolumeAndShowNotification(this, true);//系统自动控制音量增加减小级别 } else {//下滑 // VideoUtils.setVoiceVolume(this, -1); VideoUtils.setVoiceVolumeAndShowNotification(this, false); } } } return true; } @Override public boolean onDown(MotionEvent e) { return true; } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { return true; } @Override public void onLongPress(MotionEvent e) { } @Override public void onShowPress(MotionEvent e) { } @Override public boolean onSingleTapUp(MotionEvent e) { return false; }}
工具
import java.lang.reflect.Method;import java.text.SimpleDateFormat;import java.util.Date;import android.app.Activity;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.PixelFormat;import android.graphics.drawable.Drawable;import android.media.AudioManager;import android.media.MediaMetadataRetriever;import android.media.ThumbnailUtils;import android.net.ConnectivityManager;import android.net.NetworkInfo;import android.os.Build;import android.provider.MediaStore.Video;import android.provider.Settings;import android.provider.Settings.SettingNotFoundException;import android.util.Log;import android.view.View;import android.view.Window;import android.view.WindowManager;import android.widget.RelativeLayout;import android.widget.RelativeLayout.LayoutParams;import android.widget.VideoView;public class VideoUtils { /** * 根据手机的分辨率从 dp或 sp 的单位 转成为 px */ public static int dp2px(Context context, float dpValue) { float scale = context.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } /** * 根据手机的分辨率从 px 的单位转成为 dp 或 sp */ public static int px2dp(Context context, float pxValue) { float scale = context.getResources().getDisplayMetrics().density; return (int) (pxValue / scale + 0.5f); } /** * 获取屏幕高度 */ public static int getScreenHeight(Context context) { return context.getResources().getDisplayMetrics().heightPixels; } /** * 获取屏幕宽度 */ public static int getScreenWidth(Context context) { return context.getResources().getDisplayMetrics().widthPixels; } /** * 设置Activity为全屏模式 */ public static void setActivityFullScreenMode(Activity context) { context.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); } /** * 设置Activity为窗口模式??? */ public static void setActivityWindowScreenMode(Activity context) { WindowManager.LayoutParams attrs = context.getWindow().getAttributes(); attrs.flags &= (~WindowManager.LayoutParams.FLAG_FULLSCREEN); context.getWindow().setAttributes(attrs); context.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); } //******************************************************************************************************************** public static final int FULL_SCREEN = 1;//全屏拉伸模式 public static final int SCREEN_WINDOW = 2;//指定大小模式 public static final int SCREEN_WINDOW_ADAPT = 3;//自适应宽高模式 /** * 设置VideoView的全屏和窗口模式。<br> * 全屏拉伸模式 : {@link #FULL_SCREEN} <br> * 指定大小模式: {@link #SCREEN_WINDOWE}<br> * 自适应宽高模式 : {@link #SCREEN_WINDOW_ADAPT} * 这里有很多bug****************************************************************************************************************************************************** */ public static void setVideoViewLayoutParams(Activity context, VideoView mVideoView, int paramsType) { int width, height; switch (paramsType) { case FULL_SCREEN: setActivityFullScreenMode(context); RelativeLayout.LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM); layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP); layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT); layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); ((View) mVideoView.getParent()).setLayoutParams(layoutParams);//布局里我们给VideoView设置了一个父布局 mVideoView.setLayoutParams(layoutParams); break; case SCREEN_WINDOW: width = getScreenWidth(context) * 2 / 3; height = VideoUtils.getScreenHeight(context) * 2 / 3; RelativeLayout.LayoutParams LayoutParams = new LayoutParams(width, height); LayoutParams.addRule(RelativeLayout.CENTER_IN_PARENT); mVideoView.setLayoutParams(LayoutParams); break; default://先获取VideoView中资源的大小,然后分别和VideoView控件的大小作对比,当资源宽高大于控件时,缩小,否则放大。 //和加载图片一个样,但是VideoView没有scaleType塑性 int videoWidth = mVideoView.getWidth(); int videoHeight = mVideoView.getHeight(); break; } } //******************************************************************************************************************** /** * 获取屏幕亮度模式,返回-1代表没有获取到 * 自动调节:Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC=1 * 手动调节:SCREEN_BRIGHTNESS_MODE_MANUAL=0 */ public static int getScreenBrightnessMode(Context context) { int screenMode = -1; try { screenMode = Settings.System.getInt(context.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE); } catch (SettingNotFoundException e) { e.printStackTrace(); } return screenMode; } /** * 设置屏幕亮度模式 * 自动调节:Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC=1 * 手动调节:SCREEN_BRIGHTNESS_MODE_MANUAL=0 */ public static void setScreenBrightnessMode(Context context, int value) { Settings.System.putInt(context.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE, value); } /** * 获取屏幕亮度,获取失败返回-1 */ public static int getScreenBrightness(Context context) { int bright = -1; try { bright = Settings.System.getInt(context.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS); } catch (SettingNotFoundException e) { e.printStackTrace(); } return bright; } /** * 增加或减小当前屏幕亮度,并在整个系统上生效 */ public static void setScreenBrightness(Activity context, float value) { //设置当前【activity】的屏幕亮度 Window mWindow = context.getWindow(); WindowManager.LayoutParams mParams = mWindow.getAttributes();//注意:它的值是从0到1,亮度从暗到全亮 mParams.screenBrightness += value / 255.0F; if (mParams.screenBrightness > 1) {//设置大于1的值后,虽然获取到的此参数的值被改了,但系统并不使用此值而是使用某一指定值设置亮度 mParams.screenBrightness = 1; } else if (mParams.screenBrightness < 0.01) { mParams.screenBrightness = 0.01f; } mWindow.setAttributes(mParams); // 保存设置为【系统】屏幕亮度值。注意它的值是0-255 int newValue = (int) (mParams.screenBrightness * 255.0F + value);// 或者= (int) (getScreenBrightness(context) + value); if (newValue > 255) newValue = 255; else if (newValue < 0) newValue = 0; Log.i("bqt", "亮度=" + mParams.screenBrightness + ",亮度=" + newValue); Settings.System.putInt(context.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, newValue); } //******************************************************************************************************************** /** * 设置铃声模式 * @param mode 声音模式:AudioManager.RINGER_MODE_NORMAL;静音模式:_SILENT;震动模式:_VIBRATE */ public static void setRingerMode(Context context, int mode) { AudioManager mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); mAudioManager.setRingerMode(mode); } /** * 增加或减小媒体音量 */ public static void setVoiceVolume(Context context, int value) { AudioManager mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); // 注意:分为静音(0),震动(0),1--7 共九个等级。从静音调为1时,需要调大两个等级;从1调为0时,手机将调整为“震动模式” int currentVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC); //尼玛,我获得的最大值是15 int maxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); int newVolume = currentVolume + value; if (newVolume > maxVolume) { newVolume = maxVolume; } else if (newVolume < 0) { newVolume = 0; } Log.i("bqt", "音量=" + newVolume); mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, newVolume, 0); } /** * 增加或减小媒体音量,并且显示系统音量控制提示条 */ public static void setVoiceVolumeAndShowNotification(Context context, boolean isAddVolume) { AudioManager mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); if (isAddVolume) { //参数:声音类型,调整音量的方向(只能是增加、减小、不变),可选的标志位(不知道有卵用) //音乐:AudioManager.STREAM_MUSIC;通话:_VOICE_CALL;系统:_SYSTEM;铃声:_RING;提示音:_NOTIFICATION;闹铃:_ALARM mAudioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_RAISE, AudioManager.FX_FOCUS_NAVIGATION_UP); } else { mAudioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_LOWER, AudioManager.FX_FOCUS_NAVIGATION_UP); } Log.i("bqt", "音量=" + mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC)); } //******************************************************************************************************************** /** * 获取视频长度,获取网络视频长度时异常! */ public static String getVideoLength(String filePath) { MediaMetadataRetriever retriever = new MediaMetadataRetriever(); retriever.setDataSource(filePath); String length = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION); return length; } /** * 毫秒值装换为时分秒形式 */ @SuppressWarnings("deprecation") public static String long2Time(long timeLong) { Date date = new Date(timeLong); date.setHours(date.getHours() - 8); //沃日,我们这里比标准时长快了八个小时 SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss "); return format.format(date); } /** * 获取视频缩略图 * @param filePath 视频文件的路径 */ public static Bitmap createVideoThumbnail(String filePath) { return ThumbnailUtils.createVideoThumbnail(filePath, Video.Thumbnails.MINI_KIND); } /** * 获取视频的缩略图 * 先通过ThumbnailUtils来创建一个视频的缩略图,然后再利用ThumbnailUtils来生成指定大小的缩略图。 * 如果想要的缩略图的宽和高都小于MICRO_KIND,则类型要使用MICRO_KIND作为kind的值,这样会节省内存。 * @param videoPath 视频的路径 * @param width 指定输出视频缩略图的宽度 * @param height 指定输出视频缩略图的高度度 * @param kind 参照Thumbnails类中的常量MINI_KIND(512 x 384) 和 MICRO_KIND(96 x 96) */ public static Bitmap getVideoThumbnail(String videoPath, int width, int height, int kind) { // 获取视频的缩略图 Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(videoPath, kind); bitmap = ThumbnailUtils.extractThumbnail(bitmap, width, height, ThumbnailUtils.OPTIONS_RECYCLE_INPUT); return bitmap; } /** * 利用反射的方式获取视频缩略图,不建议使用 * @param filePath 视频文件的路径 */ public static Bitmap createVideoThumbnail2(String filePath) { Class<?> clazz = null; Object instance = null; try { clazz = Class.forName("android.media.MediaMetadataRetriever"); instance = clazz.newInstance(); Method method = clazz.getMethod("setDataSource", String.class); method.invoke(instance, filePath); if (Build.VERSION.SDK_INT <= 9) { return (Bitmap) clazz.getMethod("captureFrame").invoke(instance); } else { byte[] data = (byte[]) clazz.getMethod("getEmbeddedPicture").invoke(instance); if (data != null) { Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); if (bitmap != null) return bitmap; } return (Bitmap) clazz.getMethod("getFrameAtTime").invoke(instance); } } catch (Exception ex) { } finally { try { if (instance != null) { clazz.getMethod("release").invoke(instance); } } catch (Exception ignored) { } } return null; } /** * 将Drawable转化为Bitmap */ public static Bitmap drawableToBitmap(Drawable drawable) { // 取 drawable 的长宽,颜色格式 int w = drawable.getIntrinsicWidth(); int h = drawable.getIntrinsicHeight(); Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; // 创建对应 bitmap Bitmap bitmap = Bitmap.createBitmap(w, h, config); Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, w, h); drawable.draw(canvas); return bitmap; } //******************************************************************************************************************** public static final int NETWORK_TYPE_INVALID = 0; public static final int NETWORK_TYPE_MOBILE = 1; public static final int NETWORK_TYPE_WIFI = 2; /** * 获取当前网络连接状况 * 网络不可用 : {@link #NETWORK_TYPE_INVALID} <br> * 蜂窝网络(手机流量) : {@link #NETWORK_TYPE_MOBILE}<br> * WIFI连接 : {@link #NETWORK_TYPE_WIFI} */ public static int getNetworkType(Context context) { ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo networkInfo = manager.getActiveNetworkInfo(); if (networkInfo != null && networkInfo.isConnected()) { String type = networkInfo.getTypeName(); if (type.equalsIgnoreCase("WIFI")) { return NETWORK_TYPE_WIFI; } else if (type.equalsIgnoreCase("MOBILE")) { return NETWORK_TYPE_MOBILE; } } return NETWORK_TYPE_INVALID; }}
布局
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#300f" android:padding="5dp" > <RelativeLayout android:id="@+id/rl_vv" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerInParent="true" android:layout_weight="2016" android:background="#30f0" android:minHeight="200dp" android:padding="5dp" > <VideoView android:id="@+id/mVideoView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:padding="5dp" /> </RelativeLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:orientation="horizontal" > <Button android:id="@+id/btn_start" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="播放/暂停" /> <Button android:id="@+id/btn_switch" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="横竖屏切换" /> <Button android:id="@+id/btn_fullscreen" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="全屏" /> </LinearLayout> <ProgressBar android:id="@+id/progressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" /></RelativeLayout>
清单文件
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.bqt.videoview" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="17" android:targetSdkVersion="21" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- 网络权限 --> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- 滑动改变屏幕亮度/音量 --> <uses-permission android:name="android.permission.WRITE_SETTINGS" /> <uses-permission android:name="android.permission.VIBRATE" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:configChanges="keyboard|orientation|screenSize" android:label="@string/app_name" android:theme="@style/Theme.AppCompat.Light.NoActionBar" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application></manifest>
来自为知笔记(Wiz)
相关文章推荐
- Linux下MySQL,sysbench安装使用记录
- jsp传中文到下个页面时乱码
- h5学习笔记:ul 边框引起导航偏移
- SQL批处理与事务控制
- SQL批处理与事务控制
- Android开发中Handler的经典总结
- SQL批处理与事务控制
- 设计模式学习--模板方法模式
- Foundation => Objective-C _ Part2
- 网络框架的封装(一)
- 虚函数组实现虚级联继承 - 全开放和(接近)全闭合模式
- Android应用环境的下载
- Part 19 AngularJS Services
- 网络编程中的心跳机制
- UVa 156 - Ananagrams
- Atitit.在线充值功能的设计
- Mysql基本语句
- MySql 1030 Error
- vmware
- Atitit.在线充值功能的设计