基于VideoView 可调节进度的电视端的简单视频播放器

基于VideoView 可调节进度的电视端的简单视频播放器

Android 中VideoVIew的主要过程:
1.播放
2.播放器的播放监听(准备完成、播放信息、播放完成、播放出错)
3.进度条控制(快进、快退、暂停)
下面进行介绍:
一:播放
VideoView的中,设置setVideoPath()或者setVideoURI()则可以进行播放。
当成功载入视频后,会调用onPreparedListener().进行播放视频。

  mVideoView.setVideoPath("//url");
  mVideoView.setOnPreparedListener(new
      MediaPlayer.OnPreparedListener() {
       @Override
        public void onPrepared(MediaPlayer mp) {
        		//准备完成进行播放。
				mp.start();
				//监听播放完成
			    mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
       			 @Override
       			 public void onCompletion(MediaPlayer mediaPlayer) {
      		     //播放完成,并停止更新播放进度条。
       			 }
   				 }
			 }
		  })

二:监听VideoView的播放情况。

	mVideoView.setOnInfoListener(new MediaPlayer.OnInfoListener() {
        @Override
        public boolean onInfo(MediaPlayer mediaPlayer, int what, int i1) {
            switch (what) {
                case MediaPlayer.MEDIA_INFO_BUFFERING_START:
                    //显示加载动画
                    break;
                case MediaPlayer.MEDIA_INFO_BUFFERING_END:
                    //取消加载动画
                default:
                    break;
            }
            return false;
        })
    mVideoView.setOnErrorListener(new MediaPlayer.OnErrorListener() {
        @Override
        public boolean onError(MediaPlayer mediaPlayer, int i, int i1) {
       		 //提示播放错误
            return false;
        }
     )
    

三:进度条的更新
1.注意: 让控制条监听按键,但不能return true去消费左右按键,因为如果消费掉,则不能监听到seekbar的左右快进/快退事件。


mSeekBar.setOnKeyListener(new View.OnKeyListener() {
        @Override
        public boolean onKey(View view, int keycode, KeyEvent event) {
            if (event.getAction() == KeyEvent.ACTION_DOWN) {
                //当左右键按下时,①显示快进/快退②控制进度条
                switch (keycode) {
                    case KeyEvent.KEYCODE_DPAD_LEFT:
                        mPlayingRewIv.setVisibility(View.VISIBLE);
                        //此处不return true 不进行消费 下面同里
                        break;
                    case KeyEvent.KEYCODE_DPAD_RIGHT:
                        mPlayingFfIv.setVisibility(View.VISIBLE);
                        break;
                 //当按下中间键,暂停/继续播放
                    case KeyEvent.KEYCODE_DPAD_CENTER:
                        break;
                    default:
                        break;
                }
            } else if (event.getAction() == KeyEvent.ACTION_UP) {
               //当左右键抬起时,隐藏左右键提示。
                switch (keycode) {
                    case KeyEvent.KEYCODE_DPAD_LEFT:
                        mPlayingRewIv.setVisibility(View.GONE);
                        break;
                    case KeyEvent.KEYCODE_DPAD_RIGHT:
                        mPlayingFfIv.setVisibility(View.GONE);
                        break;
                    default:
                        break;
                }
            }
            // 不进行return true 
            return false;
        }
    })
	mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean b) {
          //监听seekbar的滑动事件
        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {
           //遥控器控制可以忽略此处
        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
              //遥控器控制可以忽略此处
        }
    };)

主要代码如下:
playActivity.java

package com.example.playerproject;

import android.annotation.SuppressLint;
import android.media.MediaPlayer;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.PopupWindow;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextClock;
import android.widget.TextView;
import android.widget.VideoView;

import com.example.playerproject.utils.DateUtils;
import com.github.ybq.android.spinkit.SpinKitView;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;

 
public class PlayActivity extends AppCompatActivity {
    @BindView(R.id.video_view)
    VideoView mVideoView;
    @BindView(R.id.channel_name_tv)
    TextView mChannelNameTv;
    @BindView(R.id.current_time_tv)
    TextClock mCurrentTimeTv;
    @BindView(R.id.playing_ff_iv)
    ImageView mPlayingFfIv;
    @BindView(R.id.playing_rew_iv)
    ImageView mPlayingRewIv;
    @BindView(R.id.current_play_times_tv)
    TextView mCurrentPlayTimesTv;
    @BindView(R.id.seekbar)
    SeekBar mSeekBar;
    @BindView(R.id.videoTimes)
    TextView mVideoTimesTv;
    @BindView(R.id.pause_iv)
    ImageView mPauseIv;
    @BindView(R.id.controller_rl)
    RelativeLayout mControllerRl;
    @BindView(R.id.video_loading)
    SpinKitView mVideoLoading;
    private long videoTimes;
    private static final int UPDATE_UI = 1;
    private static final int SEEK_TO = 2;
    private static final String TAG = "PlayActivity";
    private TextView slideTimesTv;
    private PopupWindow indicator;
    private int mSeekBarLength = 1464;
    private boolean isSeeking;
    private int maxProgress;
    private MediaPlayer.OnPreparedListener mOnPreparedListener = new MediaPlayer.OnPreparedListener() {
        @Override
        public void onPrepared(MediaPlayer mp) {
            Log.i(TAG, "onPrepared: ");
            mp.start();
            videoTimes = mp.getDuration();
            mHandler.sendEmptyMessageDelayed(UPDATE_UI, 1000);
            if (videoTimes > 0) {
                String totalTime = DateUtils.showTime(videoTimes / 1000);
                mVideoTimesTv.setText(totalTime);
            }
            maxProgress = mp.getDuration();
            mSeekBar.setMax(maxProgress);
            //设置滑动完成监听
            mp.setOnSeekCompleteListener(mOnSeekCompleteListener);
        }
    };

    private MediaPlayer.OnInfoListener mOnInfoListener = new MediaPlayer.OnInfoListener() {
        @Override
        public boolean onInfo(MediaPlayer mediaPlayer, int what, int i1) {
            switch (what) {
                case MediaPlayer.MEDIA_INFO_BUFFERING_START:
                    mVideoLoading.setVisibility(View.VISIBLE);
                    break;
                case MediaPlayer.MEDIA_INFO_BUFFERING_END:
                    mVideoLoading.setVisibility(View.INVISIBLE);
                default:
                    break;
            }
            return false;
        }
    };
    
    private MediaPlayer.OnErrorListener mOnErrorListener = new MediaPlayer.OnErrorListener() {
        @Override
        public boolean onError(MediaPlayer mediaPlayer, int i, int i1) {
            return false;
        }
    };

    private MediaPlayer.OnSeekCompleteListener mOnSeekCompleteListener = new MediaPlayer.OnSeekCompleteListener() {
        @Override
        public void onSeekComplete(MediaPlayer mediaPlayer) {
            mVideoView.start();
            mHandler.sendEmptyMessageDelayed(UPDATE_UI, 500);
        }
    };
    private MediaPlayer.OnCompletionListener mOnCompletionListener = new MediaPlayer.OnCompletionListener() {
        @Override
        public void onCompletion(MediaPlayer mediaPlayer) {
            mHandler.removeMessages(UPDATE_UI);
        }
    };

    @SuppressLint("HandlerLeak")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_play);
        ButterKnife.bind(this);
        mVideoView.setVideoPath("http://flv2.bn.netease.com/videolib3/1611/28/nNTov5571/SD/nNTov5571-mobile.mp4");
        initVideoViewListener();
        initSeekBar();
        //http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4
        //http://gslb.miaopai.com/stream/oxX3t3Vm5XPHKUeTS-zbXA__.mp4
        //http://flv2.bn.netease.com/videolib3/1611/28/nNTov5571/SD/nNTov5571-mobile.mp4
        initIndicator();
    }

    private void initIndicator() {
        View popView = LayoutInflater.from(this).inflate(R.layout.popwindow_indicator, null);
        indicator = new PopupWindow(popView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, false);
        slideTimesTv = popView.findViewById(R.id.seek_time);
    }

    private View.OnKeyListener mOnKeyListener = new View.OnKeyListener() {
        @Override
        public boolean onKey(View view, int keycode, KeyEvent event) {
            if (event.getAction() == KeyEvent.ACTION_DOWN) {
                isSeeking = true;
                mHandler.removeCallbacksAndMessages(null);
                switch (keycode) {
                    case KeyEvent.KEYCODE_DPAD_LEFT:
                        mPlayingRewIv.setVisibility(View.VISIBLE);
                        break;
                    case KeyEvent.KEYCODE_DPAD_RIGHT:
                        mPlayingFfIv.setVisibility(View.VISIBLE);
                        break;
                    case KeyEvent.KEYCODE_DPAD_CENTER:
                        if (mVideoView.isPlaying()) {
                            showPauseIv();
                            mVideoView.pause();
                        }
                        break;
                    default:
                        break;
                }
            } else if (event.getAction() == KeyEvent.ACTION_UP) {
                isSeeking = false;
                mHandler.sendEmptyMessage(SEEK_TO);
                switch (keycode) {
                    case KeyEvent.KEYCODE_DPAD_LEFT:
                        mPlayingRewIv.setVisibility(View.GONE);
                        break;
                    case KeyEvent.KEYCODE_DPAD_RIGHT:
                        mPlayingFfIv.setVisibility(View.GONE);
                        break;
                    default:
                        break;
                }
            }
            return false;
        }
    };

    private void hidePauseIv() {
        for (int i = 0; i < mControllerRl.getChildCount(); i++) {
            mControllerRl.getChildAt(i).setVisibility(View.VISIBLE);
        }
        mVideoLoading.setVisibility(View.GONE);
        mPauseIv.setVisibility(View.GONE);
        mPlayingFfIv.setVisibility(View.GONE);
        mPlayingRewIv.setVisibility(View.GONE);
        mSeekBar.requestFocus();
    }

    private void showPauseIv() {
        for (int i = 0; i < mControllerRl.getChildCount(); i++) {
            mControllerRl.getChildAt(i).setVisibility(View.INVISIBLE);
        }
        mPauseIv.setVisibility(View.VISIBLE);
        mPauseIv.requestFocus();
    }

    private SeekBar.OnSeekBarChangeListener mOnSeekBarChangeListener = new SeekBar.OnSeekBarChangeListener() {
        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean b) {
            Log.i(TAG, "onProgressChanged: " + progress);
            int xoff2 = 0;
            if (maxProgress != 0) {
                xoff2 = progress * mSeekBarLength / maxProgress;
                Log.i(TAG, "onxOff: " + xoff2);
            }
            if (isSeeking) {
                indicator.showAtLocation(mSeekBar, Gravity.NO_GRAVITY, 228, 965);
                indicator.update(228 + xoff2, 965, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
            } else {
                indicator.dismiss();
            }
            String mTimePass = DateUtils.showTime(seekBar.getProgress() / 1000);
            slideTimesTv.setText(mTimePass);
        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {
            Log.i(TAG, "onStartTrackingTouch: ");
        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
            Log.i(TAG, "onStopTrackingTouch: ");
        }
    };

    @SuppressLint("HandlerLeak")
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case UPDATE_UI:
                    updateProgress();
                    mHandler.sendEmptyMessageDelayed(UPDATE_UI, 1000);
                    break;
                case SEEK_TO:
                    mVideoView.seekTo(mSeekBar.getProgress());
                    break;
                default:
                    break;
            }
        }
    };

    @OnClick(R.id.pause_iv)
    public void onViewClicked(View v) {
        switch (v.getId()) {
            case R.id.pause_iv:
                hidePauseIv();
                if (!mVideoView.isPlaying()) {
                    mVideoView.start();
                }
                break;
        }
    }

    private void initSeekBar() {
        mSeekBar.requestFocus();
        mSeekBar.setOnKeyListener(mOnKeyListener);
        mSeekBar.setOnSeekBarChangeListener(mOnSeekBarChangeListener);
        
    }

    private void initVideoViewListener() {
        mVideoView.setOnPreparedListener(mOnPreparedListener);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            mVideoView.setOnInfoListener(mOnInfoListener);
        }
        mVideoView.setOnCompletionListener(mOnCompletionListener);
        mVideoView.setOnErrorListener(mOnErrorListener);
    }


    private void updateProgress() {
        mSeekBar.setProgress(mVideoView.getCurrentPosition());
        mCurrentPlayTimesTv.setText(DateUtils.showTime(mVideoView.getCurrentPosition() / 1000));
    }
}

activity_play.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
<VideoView
    android:id="@+id/video_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

<include layout="@layout/video_controller"/>

</android.support.constraint.ConstraintLayout>

video_controller.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    android:id="@+id/controller_rl"
    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:paddingLeft="@dimen/d85"
    android:paddingRight="@dimen/d86"
    android:paddingTop="@dimen/d50">

    <TextView
        android:id="@+id/channel_name_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="熊出没之探险记"
        android:textColor="@color/color_write"
        android:textSize="@dimen/d48"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_marginRight="@dimen/d204"
        android:drawableLeft="@mipmap/playing_back"
        android:text="返回键退出回看"
        android:textColor="@color/color_write"
        android:textSize="@dimen/d30"/>

    <TextClock
        android:id="@+id/current_time_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:format24Hour="HH:mm:ss"
        android:textColor="@color/color_write"
        tools:targetApi="jelly_bean_mr1"/>

    <com.github.ybq.android.spinkit.SpinKitView
        android:id="@+id/video_loading"
        style="@style/SpinKitView.Circle"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:layout_centerInParent="true"
        android:layout_gravity="center"
        android:padding="10dp"
        app:SpinKit_Color="#9e9e9e"/>

    <ImageView
        android:id="@+id/playing_ff_iv"
        android:layout_width="@dimen/d150"
        android:layout_height="@dimen/d150"
        android:layout_centerInParent="true"
        android:src="@mipmap/playing_ff"
        android:visibility="gone"/>

    <ImageView
        android:id="@+id/playing_rew_iv"
        android:layout_width="@dimen/d150"
        android:layout_height="@dimen/d150"
        android:layout_centerInParent="true"
        android:src="@mipmap/playing_rew"
        android:visibility="gone"/>

    <TextView
        android:id="@+id/current_play_times_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="@dimen/d50"
        android:text="00:00:00"
        android:textColor="@color/color_write"
        android:textSize="@dimen/d30"/>


    <SeekBar
        android:id="@+id/seekbar"
        android:layout_width="@dimen/d1464"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="@dimen/d67"
        android:layout_marginLeft="@dimen/d8"
        android:background="@null"
        android:focusable="true"
        android:maxHeight="@dimen/d2"
        android:minHeight="@dimen/d2"
        android:progressDrawable="@drawable/play_progress_style"
        android:splitTrack="false"
        android:thumb="@null"/>

    <TextView
        android:id="@+id/videoTimes"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_marginBottom="@dimen/d50"
        android:text="00:00:00"
        android:textColor="@color/color_write"
        android:textSize="@dimen/d30"/>

    <ImageView
        android:id="@+id/pause_iv"
        android:layout_width="@dimen/d100"
        android:layout_height="@dimen/d100"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_marginBottom="@dimen/d50"
        android:focusable="true"
        android:src="@mipmap/playing_pause"
        android:visibility="gone"/>

</RelativeLayout>

popwindow_indicator.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView
    android:id="@+id/seek_time"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:background="#FFC700"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="00:00:00"
    android:paddingLeft="@dimen/d2"
    android:paddingRight="@dimen/d2">

</TextView>

DateUtils.java

public class DateUtils {

    public static ArrayList<String> getEpgData() {
        ArrayList<String> list = new ArrayList<>();
        long now = System.currentTimeMillis();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        list.clear();
        int oneWeek = 7;
        for (int i = oneWeek; i >= 0; i--) {
            if (i == 0) {
                continue;
            }
            Date date = new Date(now - i * 24 * 60 * 60 * 1000); //7 6 5 4 3 2 1
            list.add(sdf.format(date));
        }
        for (int i = 0; i < oneWeek; ++i) { //now 1 2 3 4 5 6
            Date date = new Date(now + i * 24 * 60 * 60 * 1000);
            list.add(sdf.format(date));
        }
        return list;
    }
    /**
     * 获取系统当前所在时区
     * @return
     */
    public static int getCurrentTimeZone() {
        // TimeZone.setDefault(TimeZone.getTimeZone("GMT+4"));///设置系统所在时区
        int timeZone = Calendar.getInstance().getTimeZone().getOffset(System.currentTimeMillis());
        timeZone /= 3600000; // 确定时区
        return timeZone;
    }

    public static String getMonth() {
        String month = null;
        Calendar calendar = Calendar.getInstance();
        Log.e("getMonth", "calendar.get(Calendar.MONTH)=" + calendar.get(Calendar.DAY_OF_MONTH));
        int m = calendar.get(Calendar.MONTH);
        switch (m) {
            case 0:
                month = "January " + calendar.get(Calendar.DAY_OF_MONTH);
                break;
            case 1:
                month = "February " + calendar.get(Calendar.DAY_OF_MONTH);
                break;
            case 2:
                month = "March " + calendar.get(Calendar.DAY_OF_MONTH);
                break;
            case 3:
                month = "April " + calendar.get(Calendar.DAY_OF_MONTH);
                break;
            case 4:
                month = "May " + calendar.get(Calendar.DAY_OF_MONTH);
                break;
            case 5:
                month = "June " + calendar.get(Calendar.DAY_OF_MONTH);
                break;
            case 6:
                month = "July " + calendar.get(Calendar.DAY_OF_MONTH);
                break;
            case 7:
                month = "August " + calendar.get(Calendar.DAY_OF_MONTH);
                break;
            case 8:
                month = "September " + calendar.get(Calendar.DAY_OF_MONTH);
                break;
            case 9:
                month = "October " + calendar.get(Calendar.DAY_OF_MONTH);
                break;
            case 10:
                month = "November " + calendar.get(Calendar.DAY_OF_MONTH);
                break;
            case 11:
                month = "December " + calendar.get(Calendar.DAY_OF_MONTH);
                break;

            default:
                break;
        }
        return month;
    }

    /**
     * 将长时间格式字符串转换为字符串 HH:mm:ss
     *
     * @param time
     * @return String
     */
    public static String showTime(long time) {
        int minute = (int) time / 60;
        int hour = minute / 60;
        int second = (int) time % 60;
        minute %= 60;
        return String.format("%02d:%02d:%02d", hour, minute, second);
    }

    /**
     *
     * @param mss
     * @return HH:mm
     */
    public static String showHours(long mss) {
        SimpleDateFormat sdformat = new SimpleDateFormat("HH:mm");//24小时制
        return sdformat.format(mss);
    }

    /**
     * 将时间戳转换为日期格式
     *
     * @param time
     * @return
     */
    public static String showDate(long time) {
        SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy");
        String date = format.format(time);
        return TextUtils.isEmpty(date) ? "" : date;
    }
    public static long getMillisecond(String data) {
        DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        long time = System.currentTimeMillis();
        try {
            Date dateTime = format.parse(data);
            time = dateTime.getTime();

        } catch (ParseException e) {
            e.printStackTrace();
        }
        return time;
    }
    public static ArrayList<String> getLastWeek() {
        ArrayList<String> list = new ArrayList<>();
        long now = System.currentTimeMillis();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        list.clear();
        int oneWeek = 7;
        for (int i = oneWeek; i >= 0; i--) {
            if (i == 0) {
                continue;
            }
            //前七天 0 - 6
            Date date = new Date(now - i * 24 * 60 * 60 * 1000);
            list.add(sdf.format(date));
        }
        for (int i = 0; i < oneWeek; ++i) {
            //后七天 7 - 13
            Date date = new Date(now + i * 24 * 60 * 60 * 1000);
            list.add(sdf.format(date));
        }
        return list;
    }

}

源码地址

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值