欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android自定義播放器控件VideoView

 更新時(shí)間:2016年01月29日 15:20:22   作者:So,Cool  
這篇文章主要介紹了Android自定義播放器控件VideoView的相關(guān)資料,需要的朋友可以參考下

介紹

最近要使用播放器做一個(gè)簡(jiǎn)單的視頻播放功能,開始學(xué)習(xí)VideoView,在橫豎屏切換的時(shí)候碰到了點(diǎn)麻煩,不過在查閱資料后總算是解決了。在寫VideoView播放視頻時(shí)候定義控制的代碼全寫在Actvity里了,寫完一看我靠代碼好亂,于是就寫了個(gè)自定義的播放器控件,支持指定大小,可以橫豎屏切換,手動(dòng)左右滑動(dòng)快進(jìn)快退。好了,下面開始。

效果圖有點(diǎn)卡,我也不知道為啥。。。。。

VideoView介紹

這個(gè)是我們實(shí)現(xiàn)視頻播放最主要的控件,詳細(xì)的介紹大家百度就去看,這里介紹幾個(gè)常用的方法。

用于播放視頻文件。 VideoView 類可以從不同的來源(例如資源文件或內(nèi)容提供器) 讀取圖像,計(jì)算和維護(hù)視頻的畫面尺寸以使其適用于任何布局管理器, 并提供一些諸如縮放、著色之類的顯示選項(xiàng)。

VideoView 常用的幾個(gè)方法

public int getDuration ()

獲得所播放視頻的總時(shí)間

public int getCurrentPosition ()

獲得當(dāng)前的位置,我們可以用來設(shè)置播放時(shí)間的顯示

public int getCurrentPosition ()

獲得當(dāng)前的位置,我們可以用來設(shè)置播放時(shí)間的顯示

public int pause ()

暫停播放

public int seekTo ()

設(shè)置播放位置,我們用來總快進(jìn)的時(shí)候就能用到

public int setOnCompletionListener(MediaPlayer.OnCompletionListener l)

注冊(cè)在媒體文件播放完畢時(shí)調(diào)用的回調(diào)函數(shù)。

public int setOnErrorListener (MediaPlayer.OnErrorListener l)

注冊(cè)在設(shè)置或播放過程中發(fā)生錯(cuò)誤時(shí)調(diào)用的回調(diào)函數(shù)。如果未指定回調(diào)函數(shù), 或回調(diào)函數(shù)返回false,會(huì)彈一個(gè)dialog提示用戶不能播放

public void setOnPreparedListener (MediaPlayer.OnPreparedListener l)

注冊(cè)在媒體文件加載完畢,可以播放時(shí)調(diào)用的回調(diào)函數(shù)。

public void setVideoURI (Uri uri)

設(shè)置播放的視頻源,也可以用setVideoPath指定本地文件

public void start ()

開始播放

getHolder().setFixedSize(width,height);

設(shè)置VideoView的分辨率,如果我們的VideoView在開始播放的時(shí)候是豎屏的,當(dāng)橫屏的時(shí)候我們改變了VideoView的布局大小,就需要這個(gè)方法重新設(shè)置它的分辨率,否則你會(huì)發(fā)現(xiàn)改變了之后VideoView內(nèi)部的視頻部分還是原來的大小,這點(diǎn)要注意。

自定義播放器思路

說是自定義,其實(shí)無非就是把這些VideoView和用來顯示的其它控件結(jié)合在一起,然后在內(nèi)部處理它的事件交互,我們要做的就是以下幾步:1、寫好整個(gè)空間的布局。2、在自定義控件的內(nèi)部獲取到整個(gè)控件內(nèi)部的各個(gè)小控件,并且為它們?cè)O(shè)置一些初始化事件。3、根據(jù)你自己的邏輯和想實(shí)現(xiàn)的效果在里面寫自己的事件處理,需要在和外部進(jìn)行交互就提供方法和接口咯。最后就是使用測(cè)試效果了。好了,我們就跟著這里說的4步去實(shí)現(xiàn)吧!

具體實(shí)現(xiàn)

1、第一步,寫自己的布局文件

想要的效果就是在底部放一個(gè)狀態(tài)欄顯示時(shí)間等信息,播放進(jìn)度,進(jìn)入全屏,中間放一個(gè)快進(jìn)快退的狀態(tài),布局代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/viewBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:descendantFocusability="beforeDescendants">
<com.qiangyu.test.commonvideoview.MyVideoView
android:id="@+id/videoView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
//底部狀態(tài)欄
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="#CC282828"
android:padding="3dip"
android:id="@+id/videoControllerLayout"
android:gravity="center"
android:layout_gravity="bottom">
<LinearLayout android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:id="@+id/videoPauseBtn"
android:paddingRight="10dip"
android:paddingLeft="10dp">
<ImageView android:layout_width="22dp"
android:layout_height="22dp"
android:id="@+id/videoPauseImg" />
</LinearLayout>
<LinearLayout android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal"
android:paddingRight="0dip">
<SeekBar android:layout_width="fill_parent"
android:id="@+id/videoSeekBar"
android:layout_weight="1"
style="@android:style/Widget.Holo.SeekBar"
android:layout_height="wrap_content"/>
<TextView android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:gravity="center"
android:text="00:00"
android:textSize="12dp"
android:id="@+id/videoCurTime"
android:textColor="#FFF"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:textSize="12dp"
android:textColor="#FFF"
android:text="/"/>
<TextView android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:gravity="center"
android:text="00:00"
android:textSize="12dp"
android:id="@+id/videoTotalTime"
android:textColor="#FFF"
android:layout_marginRight="10dp"
/>
</LinearLayout>
<LinearLayout
android:id="@+id/screen_status_btn"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center">
<ImageView
android:id="@+id/screen_status_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/iconfont_enter_32"/>
</LinearLayout>
</LinearLayout>
//VideoVIEW中間的開始按鈕和進(jìn)度條以及快進(jìn)快退的提示
<ProgressBar android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:id="@+id/progressBar"
style="@android:style/Widget.Holo.ProgressBar.Small"/>
<ImageView android:layout_width="30dip"
android:layout_height="30dip"
android:id="@+id/videoPlayImg"
android:layout_gravity="center"
android:src="@mipmap/video_box_play"/>
<LinearLayout
android:id="@+id/touch_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_gravity="center"
android:visibility="invisible"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:background="#000">
<ImageView android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:id="@+id/touchStatusImg"/>
<TextView
android:id="@+id/touch_time"
android:layout_width="wrap_content"
android:text="25:00/59:00"
android:textSize="12sp"
android:textColor="#fff"
android:layout_height="wrap_content"/>
</LinearLayout>
</FrameLayout> 

上面的布局很簡(jiǎn)單,VideoView用了自定義是因?yàn)楫?dāng)布局改變的時(shí)候,要讓VideoView重新獲取布局位置,在里面設(shè)置它的分辨率為全屏.VideoView的代碼如下

public class MyVideoView extends VideoView {
public MyVideoView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public MyVideoView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyVideoView(Context context) {
super(context);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = getDefaultSize(0, widthMeasureSpec);
int height = getDefaultSize(0, heightMeasureSpec);
this.getHolder().setFixedSize(width,height);//設(shè)置分辨率
setMeasuredDimension(width, height);
}
}

好,布局寫好了我來第二步,獲取內(nèi)部控件初始化事件

2、第二步,onFinishInflate()中得到內(nèi)部的控件,做初始化工作

onFinishInflate方法在xml解析完畢的時(shí)候會(huì)回調(diào)該方法,一般在做組合控件的時(shí)候最常用

@Override
protected void onFinishInflate() {
super.onFinishInflate();
initView();
}
private void initView() {
View view = LayoutInflater.from(context).inflate(R.layout.common_video_view,null);
viewBox = (FrameLayout) view.findViewById(R.id.viewBox);
videoView = (MyVideoView) view.findViewById(R.id.videoView);
videoPauseBtn = (LinearLayout) view.findViewById(R.id.videoPauseBtn);
screenSwitchBtn = (LinearLayout) view.findViewById(R.id.screen_status_btn);
videoControllerLayout = (LinearLayout) view.findViewById(R.id.videoControllerLayout);
touchStatusView = (LinearLayout) view.findViewById(R.id.touch_view);
touchStatusImg = (ImageView) view.findViewById(R.id.touchStatusImg);
touchStatusTime = (TextView) view.findViewById(R.id.touch_time);
videoCurTimeText = (TextView) view.findViewById(R.id.videoCurTime);
videoTotalTimeText = (TextView) view.findViewById(R.id.videoTotalTime);
videoSeekBar = (SeekBar) view.findViewById(R.id.videoSeekBar);
videoPlayImg = (ImageView) view.findViewById(R.id.videoPlayImg);
videoPlayImg.setVisibility(GONE);
videoPauseImg = (ImageView) view.findViewById(R.id.videoPauseImg);
progressBar = (ProgressBar) view.findViewById(R.id.progressBar);
videoPauseBtn.setOnClickListener(this);
videoSeekBar.setOnSeekBarChangeListener(this);
videoPauseBtn.setOnClickListener(this);
videoView.setOnPreparedListener(this);
videoView.setOnCompletionListener(this);
screenSwitchBtn.setOnClickListener(this);
videoPlayImg.setOnClickListener(this);
//注冊(cè)在設(shè)置或播放過程中發(fā)生錯(cuò)誤時(shí)調(diào)用的回調(diào)函數(shù)。如果未指定回調(diào)函數(shù),或回調(diào)函數(shù)返回false,VideoView 會(huì)通知用戶發(fā)生了錯(cuò)誤。
videoView.setOnErrorListener(this);
viewBox.setOnTouchListener(this);
viewBox.setOnClickListener(this);
addView(view);
} 

很簡(jiǎn)單的做了代碼初始化和videoView的播放事件的注冊(cè),這里的事件待會(huì)要處理的有viewBox.setOnTouchListener(this)注冊(cè)的onTouch事件,我們要在里面寫左右滑動(dòng)快進(jìn)快退的效果,videoSeekBar.setOnSeekBarChangeListener(this);處理拖動(dòng)seekbar快進(jìn)快退。

3、第三步,事件、效果處理

viewBox.setOnTouchListener(this);

1、onTouch里的實(shí)現(xiàn)快進(jìn)快退

@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
//沒播放的時(shí)候不處理
if (!videoView.isPlaying()){
return false;
}
float downX = event.getRawX();
touchLastX = downX;
Log.d("FilmDetailActivity", "downX" + downX);
//保存當(dāng)前播放的位置用與做事件顯示
this.position = videoView.getCurrentPosition();
break;
case MotionEvent.ACTION_MOVE:
//沒播放的時(shí)候不處理
if (!videoView.isPlaying()){
return false;
}
float currentX = event.getRawX();
float deltaX = currentX - touchLastX;
float deltaXAbs = Math.abs(deltaX);
if (deltaXAbs>1){//正向移動(dòng),快進(jìn)
if (touchStatusView.getVisibility()!=View.VISIBLE){
touchStatusView.setVisibility(View.VISIBLE);
//顯示快進(jìn)的時(shí)間view
}
touchLastX = currentX;
Log.d("FilmDetailActivity","deltaX"+deltaX);
if (deltaX > 1) {
position += touchStep;
if (position > duration) {
position = duration;
}
touchPosition = position;
touchStatusImg.setImageResource(R.mipmap.ic_fast_forward_white_24dp);
int[] time = getMinuteAndSecond(position);
touchStatusTime.setText(String.format("%02d:%02d/%s", time[0], time[1],formatTotalTime));
} else if (deltaX < -1) {//快退
position -= touchStep;
if (position < 0) {
position = 0;
}
touchPosition = position;
touchStatusImg.setImageResource(R.mipmap.ic_fast_rewind_white_24dp);
int[] time = getMinuteAndSecond(position);
touchStatusTime.setText(String.format("%02d:%02d/%s", time[0], time[1],formatTotalTime));
//mVideoView.seekTo(position);
}
}
break;
case MotionEvent.ACTION_UP:
if (touchPosition!=-1){
videoView.seekTo(touchPosition);
//放開手指的時(shí)候快進(jìn)或快退到滑動(dòng)決定的時(shí)間位置 touchStatusView.setVisibility(View.GONE);
touchPosition = -1;
if (videoControllerShow){
return true;
}
}
break;
}
return false;
}

2、處理 seekBar的拖動(dòng)事件

@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
int[] time = getMinuteAndSecond(progress);
videoCurTimeText.setText(String.format("%02d:%02d", time[0], time[1]));
//設(shè)置底部時(shí)間顯示
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
videoView.pause();
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
videoView.seekTo(videoSeekBar.getProgress());
videoView.start();
videoPlayImg.setVisibility(View.INVISIBLE);
videoPauseImg.setImageResource(R.mipmap.icon_video_pause);
//拖動(dòng)之后到指定的時(shí)間位置
} 

3、videoView的回調(diào)事件

@Override
public void onPrepared(MediaPlayer mp) {
duration = videoView.getDuration();
int[] time = getMinuteAndSecond(duration);
videoTotalTimeText.setText(String.format("%02d:%02d", time[0], time[1]));
formatTotalTime = String.format("%02d:%02d", time[0], time[1]);
videoSeekBar.setMax(duration);
progressBar.setVisibility(View.GONE);
mp.start();
videoPauseBtn.setEnabled(true);
videoSeekBar.setEnabled(true);
videoPauseImg.setImageResource(R.mipmap.icon_video_pause);
timer.schedule(timerTask, 0, 1000);
//初始化總時(shí)間等一些界面顯示,同時(shí)用timer定時(shí)去修改時(shí)間進(jìn)度textView
}
@Override
public void onCompletion(MediaPlayer mp) {
videoView.seekTo(0);
videoSeekBar.setProgress(0);
videoPauseImg.setImageResource(R.mipmap.icon_video_play);
videoPlayImg.setVisibility(View.VISIBLE);
}

還有一些其它的點(diǎn)擊時(shí)間就不放了,都是暫停,播放,點(diǎn)擊顯示隱藏底部狀態(tài)欄,全屏切換等的事件。到了這里我們的事件處理完畢啦,接下來就要我們視頻怎么播放呢?為了播放我們?yōu)橥獠刻峁┮粋€(gè)方法

//開始播放
public void start(String url){
videoPauseBtn.setEnabled(false);
videoSeekBar.setEnabled(false);
videoView.setVideoURI(Uri.parse(url));
videoView.start();
}
//進(jìn)入全屏?xí)r候調(diào)用
public void setFullScreen(){
touchStatusImg.setImageResource(R.mipmap.iconfont_exit);
this.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
videoView.requestLayout();
}
//退出全屏?xí)r候調(diào)用
public void setNormalScreen(){
touchStatusImg.setImageResource(R.mipmap.iconfont_enter_32);
this.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,400));
videoView.requestLayout();
} 

上面提供的setFullScreen()和setNormalScreen()需要在Activity的 onConfigurationChanged(Configuration newConfig)橫豎屏發(fā)生改變的 回調(diào)方法里面調(diào)用,還需要注意的是我這里寫的是LinearLayout的LayoutParams,所以我們自定義的view的父空間要是LinearLayout,當(dāng)然你也可以修改。

4、控件的使用

我們只需要在獲得空間調(diào)用start方法,然后在onConfigurationChanged方法里調(diào)用setFullScreen和setNormalScreen就可以了,

布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="com.qiangyu.test.commonvideoview.MainActivity">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay"/>
<com.qiangyu.test.commonvideoview.CommonVideoView
android:id="@+id/common_videoView"
android:layout_width="match_parent"
android:layout_height="300dp" />
</LinearLayout>

activity代碼

public class MainActivity extends AppCompatActivity {
CommonVideoView videoView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.content_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
videoView = (CommonVideoView) findViewById(R.id.common_videoView);
videoView.start("你的服務(wù)器視頻地址");
}
@Override public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
videoView.setFullScreen();
}else {
videoView.setNormalScreen();
}
}
}

最后為了防止你的Activity在橫豎屏切換的時(shí)候重新創(chuàng)建別忘記在AndroidManifest.xml文件里面配置

android:configChanges=”orientation|screenSize|screenLayout”, 如果你這里有疑惑可以參考我的文章–>深入了解Activity-生命周期

<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar"
android:configChanges="orientation|screenSize|screenLayout">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

以上所述是小編給大家分享的Android自定義播放器控件VideoView的相關(guān)知識(shí),希望對(duì)大家有所幫助。

相關(guān)文章

  • ubuntu環(huán)境下反編譯android apk的方法

    ubuntu環(huán)境下反編譯android apk的方法

    今天小編就為大家分享一篇關(guān)于ubuntu環(huán)境下反編譯android apk的方法,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-03-03
  • Android打造炫酷的電影票在線選座app在線選座功能

    Android打造炫酷的電影票在線選座app在線選座功能

    這篇文章主要介紹了Android打造炫酷的電影票在線選座app在線選座功能的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2016-09-09
  • Android使用Intent發(fā)送短信的實(shí)現(xiàn)方法

    Android使用Intent發(fā)送短信的實(shí)現(xiàn)方法

    這篇文章主要介紹了Android使用Intent發(fā)送短信的實(shí)現(xiàn)方法,結(jié)合簡(jiǎn)單實(shí)例形式分析了Android短信發(fā)送功能的實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2016-07-07
  • android canvas使用line畫半圓

    android canvas使用line畫半圓

    這篇文章主要為大家詳細(xì)介紹了android canvas使用line畫半園,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-02-02
  • Android 代碼設(shè)置開機(jī)自啟動(dòng)App的方法

    Android 代碼設(shè)置開機(jī)自啟動(dòng)App的方法

    今天小編就為大家分享一篇Android 代碼設(shè)置開機(jī)自啟動(dòng)App的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-07-07
  • 談?wù)凙ndroid里的Context的使用實(shí)例

    談?wù)凙ndroid里的Context的使用實(shí)例

    這篇文章主要介紹了談?wù)凙ndroid里的Context的使用實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2016-11-11
  • android實(shí)現(xiàn)多線程斷點(diǎn)續(xù)傳功能

    android實(shí)現(xiàn)多線程斷點(diǎn)續(xù)傳功能

    這篇文章主要為大家詳細(xì)介紹了android實(shí)現(xiàn)多線程斷點(diǎn)續(xù)傳功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • Android實(shí)現(xiàn)每天定時(shí)提醒功能

    Android實(shí)現(xiàn)每天定時(shí)提醒功能

    本文主要介紹了Android每天定時(shí)提醒功能、定時(shí)功能、鬧鐘的相關(guān)知識(shí)。具有很好的參考價(jià)值,下面跟著小編一起來看下吧
    2017-04-04
  • Android 高仿微信支付數(shù)字鍵盤功能

    Android 高仿微信支付數(shù)字鍵盤功能

    現(xiàn)在很多app的支付、輸入密碼功能,都是使用自定義數(shù)字鍵盤,方便實(shí)用。下面本文給大家?guī)砹薃ndroid 高仿微信支付數(shù)字鍵盤功能,非常不錯(cuò),感興趣的朋友一起學(xué)習(xí)吧
    2016-08-08
  • Flutter 假異步的實(shí)現(xiàn)示例

    Flutter 假異步的實(shí)現(xiàn)示例

    這篇文章主要介紹了Flutter 假異步的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11

最新評(píng)論