編輯:關於Android編程
本博客用Android studio集成了vitamio的自定義視頻播放器,同時可以在文件管理中選擇播放,想要一個自己的視頻播放器這邊便可以滿足
實現具體功能如下:
1.sd卡內存視頻文件的點擊播放;
2.視頻時間進度條;
3.屏幕亮度的手勢滑動;
4.視頻音量的手勢滑動;
5.多點手勢效果
6.自定義存儲視頻url播放
想要的重要的代碼,我懂得:
------------------------------軟件工程結構圖:
最重要的是依賴上vitamio庫:
-------------------------工具類FileUtil,檢查文件格式是否屬於自己定義的格式:
public class FileUtil { public static final String[] VIDEO_EXTENSIONS = { "3gp", "amv", "avb", "avd", "avi", "flh", "fli", "flv", "flx", "gvi", "gvp", "hdmov", "hkm", "ifo", "imovi", "imovi", "iva", "ivf", "ivr", "m4v", "m75", "meta", "mgv", "mj2", "mjp", "mjpg", "mkv", "mmv", "mnv", "mod", "modd", "moff", "moi", "moov", "mov", "movie", "mp21", "mp21", "mp2v", "mp4", "mp4v", "mpe", "mpeg", "mpeg4", "mpf", "mpg", "mpg2", "mpgin", "mpl", "mpls", "mpv", "mpv2", "mqv", "msdvd", "msh", "mswmm", "mts", "mtv", "mvb", "mvc", "mvd", "mve", "mvp", "mxf", "mys", "ncor", "nsv", "nvc", "ogm", "ogv", "ogx", "osp", "par", "pds", "pgi", "piv", "playlist", "pmf", "prel", "pro", "prproj", "psh", "pva", "pvr", "pxv", "qt", "qtch", "qtl", "qtm", "qtz", "rcproject", "rdb", "rec", "rm", "rmd", "rmp", "rms", "rmvb", "roq", "rp", "rts", "rts", "rum", "rv", "sbk", "sbt", "scm", "scm", "scn", "sec", "seq", "sfvidcap", "smil", "smk", "sml", "smv", "spl", "ssm", "str", "stx", "svi", "swf", "swi", "swt", "tda3mt", "tivo", "tix", "tod", "tp", "tp0", "tpd", "tpr", "trp", "ts", "tvs", "vc1", "vcr", "vcv", "vdo", "vdr", "veg", "vem", "vf", "vfw", "vfz", "vgz", "vid", "viewlet", "viv", "vivo", "wma" }; //集合放置所有支持視頻格式 private static final List--------------------工具類FileUtil,檢查文件格式是否屬於自己定義的格式:listvideo = new ArrayList<>( Arrays.asList(VIDEO_EXTENSIONS)); // 檢測是否是視頻文件 public static boolean isVideo(String path) { path=getFileExtension(path); return listvideo.contains(path); } // 獲取文件後綴名 public static String getFileExtension(String path) { if (null != path) { // 後綴點 的位置 int dex = path.lastIndexOf("."); // 截取後綴名 return path.substring(dex + 1); } return null; } }
public class LocUtil { // 獲取所有存儲路徑 public static ListgetDirs(Context context) { List dirs = new ArrayList (); StorageManager storageManager = (StorageManager) context .getSystemService(Context.STORAGE_SERVICE); try { Class[] paramClasses = {}; Method getVolumePathsMethod = StorageManager.class.getMethod( "getVolumePaths", paramClasses); getVolumePathsMethod.setAccessible(true); Object[] params = {}; Object invoke = getVolumePathsMethod.invoke(storageManager, params); for (int i = 0; i < ((String[]) invoke).length; i++) { // System.out.println(((String[])invoke)[i]); dirs.add(((String[]) invoke)[i]); } } catch (Exception e) { e.printStackTrace(); } return dirs; } //獲取最大音量 public static int getMaxVolume(Context context) { return ((AudioManager) context.getSystemService(Context.AUDIO_SERVICE)) .getStreamMaxVolume(AudioManager.STREAM_MUSIC); } // 獲取當前音量 public static int getCurVolume(Context context) { return ((AudioManager) context.getSystemService(Context.AUDIO_SERVICE)) .getStreamVolume(AudioManager.STREAM_MUSIC); } // 設置當前音量 public static void setCurVolume(Context context, int index) { ((AudioManager) context.getSystemService(Context.AUDIO_SERVICE)) .setStreamVolume(AudioManager.STREAM_MUSIC, index, 0); } // 獲取屏幕像素 public static ScreenBean getScreenPix(Context context) { Display dplay = ((VideoPlay) context).getWindowManager() .getDefaultDisplay(); return new ScreenBean(dplay.getWidth(),dplay.getHeight()); } }
public class ScreenBean { private int sWidth; private int sHeight; public ScreenBean(int sWidth, int sHeight) { super(); this.sWidth = sWidth; this.sHeight = sHeight; } public int getsWidth() { return sWidth; } public void setsWidth(int sWidth) { this.sWidth = sWidth; } public int getsHeight() { return sHeight; } public void setsHeight(int sHeight) { this.sHeight = sHeight; } }----------------------中轉傳遞界面MainActivity類:
public class MainActivity extends AppCompatActivity { String Path; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent getPath=getIntent(); String action = getPath.getAction(); if(getPath.ACTION_VIEW.equals(action)){ Path=getPath.getDataString(); }else { Path= Environment.getExternalStorageDirectory() + "/test.mp4"; } Intent intent = new Intent(this, VideoPlay.class); intent.putExtra("videoURL",Path); startActivity(intent); finish(); } }這個界面是中轉,開發時一般自己定義,
Path=getPath.getDataString();//獲取sd卡的視頻文件url路徑
Path= Environment.getExternalStorageDirectory() + "/test.mp4"; //程序存儲的路徑,可以掃描手機內存視頻存儲到數據庫,這種視頻列表簡單自己寫.
----------------------視頻播放Activity類:
public class VideoPlay extends Activity { /** 當前視頻路徑 */ private String path; /** 當前聲音 */ private int mVolume = -1; /** 最大音量 */ private int mMaxVolume; /** 當前亮度 */ private float mBrightness = -1f; /** 手勢數目 */ private int finNum=0; private View mVolumeBrightnessLayout; private ImageView mOperationBg; private ImageView mOperationPercent; private VideoView mVideoView; private GestureDetector gestDetector; private ScaleGestureDetector scaleDetector; private ScreenBean screenBean; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); if (!LibsChecker.checkVitamioLibs(this)) return; requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_video); Intent getPath=getIntent(); path=getPath.getStringExtra("videoURL"); init(); } private void init() { mVideoView = (VideoView) findViewById(R.id.surface_view); mVolumeBrightnessLayout = findViewById(R.id.operation_volume_brightness); mOperationBg = (ImageView) findViewById(R.id.operation_bg); mOperationPercent = (ImageView) findViewById(R.id.operation_percent); mMaxVolume = LocUtil.getMaxVolume(this); gestDetector = new GestureDetector(this, new SingleGestureListener()); scaleDetector = new ScaleGestureDetector(this, new MultiGestureListener()); screenBean = LocUtil.getScreenPix(this); if (path == "") { return; } else { mVideoView.setVideoPath(path); mVideoView.setMediaController(new MediaController(this)); mVideoView.requestFocus(); mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mediaPlayer) { mediaPlayer.setPlaybackSpeed(1.0f); } }); } } /** 定時隱藏 */ private Handler mDismissHandler = new Handler() { @Override public void handleMessage(Message msg) { mVolumeBrightnessLayout.setVisibility(View.GONE); } }; @Override public boolean onTouchEvent(MotionEvent event) { // TODO Auto-generated method stub finNum=event.getPointerCount(); if (1 == finNum) { gestDetector.onTouchEvent(event); switch (event.getAction()) { case MotionEvent.ACTION_UP: endGesture(); } } else if (2 ==finNum) { scaleDetector.onTouchEvent(event); } return true; } /** 手勢結束 */ private void endGesture() { mVolume = -1; mBrightness = -1f; // 隱藏 mDismissHandler.removeMessages(0); mDismissHandler.sendEmptyMessageDelayed(0, 500); } /** * 視頻縮放 */ public void changeLayout(int size) { mVideoView.setVideoLayout(size, 0); } /** * 聲音大小 * */ public void changeVolume(float percent) { if (mVolume == -1) { mVolume = LocUtil.getCurVolume(this); if (mVolume < 0) mVolume = 0; // 顯示 mOperationBg.setImageResource(R.drawable.video_volumn_bg); mVolumeBrightnessLayout.setVisibility(View.VISIBLE); } int index = (int) (percent * mMaxVolume) + mVolume; if (index > mMaxVolume) index = mMaxVolume; else if (index < 0) index = 0; // 變更聲音 LocUtil.setCurVolume(this, index); // 變更進度條 ViewGroup.LayoutParams lp = mOperationPercent.getLayoutParams(); lp.width = findViewById(R.id.operation_full).getLayoutParams().width * index / mMaxVolume; mOperationPercent.setLayoutParams(lp); } /** * 亮度大小 * * @param percent */ public void changeBrightness(float percent) { if (mBrightness < 0) { mBrightness = getWindow().getAttributes().screenBrightness; if (mBrightness <= 0.00f) mBrightness = 0.50f; if (mBrightness < 0.01f) mBrightness = 0.01f; // 顯示 mOperationBg.setImageResource(R.drawable.video_brightness_bg); mVolumeBrightnessLayout.setVisibility(View.VISIBLE); } WindowManager.LayoutParams lpa = getWindow().getAttributes(); lpa.screenBrightness = mBrightness + percent; if (lpa.screenBrightness > 1.0f) lpa.screenBrightness = 1.0f; else if (lpa.screenBrightness < 0.01f) lpa.screenBrightness = 0.01f; getWindow().setAttributes(lpa); ViewGroup.LayoutParams lp = mOperationPercent.getLayoutParams(); lp.width = (int) (findViewById(R.id.operation_full).getLayoutParams().width * lpa.screenBrightness); mOperationPercent.setLayoutParams(lp); } /** * 單點觸屏 */ private class SingleGestureListener implements GestureDetector.OnGestureListener { @Override public boolean onDown(MotionEvent e) { // TODO Auto-generated method stub return false; } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { // TODO Auto-generated method stub Log.d("Fling", velocityY); return false; } @Override public void onLongPress(MotionEvent e) { // TODO Auto-generated method stub } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { // TODO Auto-generated method stub if(2==finNum){ return false; } float moldX = e1.getX(); float moldY = e1.getY(); float y = e2.getY(); if (moldX > screenBean.getsWidth() * 9.0 / 10)// 右邊滑動 changeVolume((moldY - y) / screenBean.getsHeight()); else if (moldX < screenBean.getsWidth() / 10.0)// 左邊滑動 changeBrightness((moldY - y) / screenBean.getsHeight()); return false; } @Override public void onShowPress(MotionEvent e) { // TODO Auto-generated method stub } @Override public boolean onSingleTapUp(MotionEvent e) { // TODO Auto-generated method stub return false; } } //多點手勢控制 private class MultiGestureListener implements OnScaleGestureListener { @Override public boolean onScale(ScaleGestureDetector detector) { // TODO Auto-generated method stub return false; } @Override public boolean onScaleBegin(ScaleGestureDetector detector) { // TODO Auto-generated method stub // 返回true ,才能進入onscale()函數 return true; } @Override public void onScaleEnd(ScaleGestureDetector detector) { // TODO Auto-generated method stub float oldDis = detector.getPreviousSpan(); float curDis = detector.getCurrentSpan(); if (oldDis - curDis > 50) { // 縮小 changeLayout(0); Toast.makeText(VideoPlay.this, "縮小", Toast.LENGTH_LONG).show(); } else if (oldDis - curDis < -50) { // 放大 changeLayout(1); Toast.makeText(VideoPlay.this, "放大", Toast.LENGTH_LONG).show(); } } } }------------視頻布局activity_video(activity_main裡面沒寫省略):
-------------Androidmanifest清單文件(4個注意點):<framelayout android:background="#00000000" android:id="@+id/operation_volume_brightness" android:layout_centerinparent="true" android:layout_height="wrap_content" android:layout_width="wrap_content" android:orientation="horizontal" android:padding="0dip" android:visibility="invisible"> <framelayout android:layout_gravity="bottom|center_horizontal" android:layout_height="wrap_content" android:layout_width="wrap_content" android:paddingbottom="25dip"> </framelayout></framelayout>
3.添加intent隱式意圖,對sd卡支持的文件格式添加本程序的打開方式:
4.添加視頻播放控制的Activity:
<activity android:name=".VideoPlay" android:screenOrientation="landscape" > </activity>-------庫和圖片資源路徑:
相關閱讀:Android開發框架之自定義ZXing二維碼掃描界面並解決取景框拉伸問題此項目源碼地址:請點擊這裡看一下zxing的項目結構,我這裡直接拿過來用的
安卓消息處理類:Looper、Handler、MessageQueue、Message、ThreadLocal、ThreadLocal.Values、HandlerThr
上一篇文章中學習了android.provider中Telephony類。這一篇文章學習android.telephony包中的類,這些類是android提供給上層調用的
在Android中,除了使用Java.NET包下的API訪問HTTP服務之外,我們還可以換一種途徑去完成工作。Android SDK附帶了Apache的HttpClien