Android自定义视频播放器(三)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zxd1435513775/article/details/81535065

参看:Android自定义视频播放器(一):https://blog.csdn.net/zxd1435513775/article/details/81507909
参看:Android自定义视频播放器(二):https://blog.csdn.net/zxd1435513775/article/details/81533053

一、引言

在上文中,我们通过自定义控制面板的布局,来实现自定义的播放控制,下面来对里面的各个组件进行事件绑定。

@Override
public void onClick(View v) {
    if ( v == btnVoice ) {
        //声音按钮,处理声音
        isMute = !isMute;
        updataVoice(currentVoice, isMute);
    } else if ( v == btnSwichPlayer ) {
        // Handle clicks for btnSwichPlayer
    } else if ( v == btnExit ) {
        // Handle clicks for btnExit
    } else if ( v == btnVideoPre ) {
        // Handle clicks for btnVideoPre
    } else if ( v == btnVideoStartPause ) {
        //播放和暂停按钮
        startAndPause();
    } else if ( v == btnVideoNext ) {
        // Handle clicks for btnVideoNext
    } else if ( v == btnVideoSiwchScreen ) {
        // Handle clicks for btnVideoSiwchScreen
    }
}

二、播放按钮和播放进度条SeekBar事件绑定

1、播放/暂停按钮事件

    //播放和暂停视频
    private void startAndPause() {
        if (videoView.isPlaying()) {
            //视频在播放-设置暂停
            videoView.pause();
            //按钮状态设置播放
            btnVideoStartPause.setBackgroundResource(R.drawable.btn_video_start_selector);
        } else {
            //视频播放
            videoView.start();
            //按钮状态设置暂停
            btnVideoStartPause.setBackgroundResource(R.drawable.btn_video_pause_selector);
        }
    }

2、播放视频进度条事件

(1)为VideoView设置的监听
    //设置视频准备好了的监听
    videoView.setOnPreparedListener(new MyPreparedListener());

    //设置视频播放出错的监听
    videoView.setOnErrorListener(new MyErrorListener());

    //设置视频播放完成的监听
    videoView.setOnCompletionListener(new MyCompletionListener());
(2)当视频准备好了,在该监听器中,为SeekBar的总长赋值,并且发送handler
 private class MyPreparedListener implements MediaPlayer.OnPreparedListener {

    @Override
    public void onPrepared(MediaPlayer mediaPlayer) {

        //视频准备好了,进行播放
        mediaPlayer.start();

        //视频的总时长,并关联SeekBar的总长度
        int duration = videoView.getDuration();

        //设置SeekBar进度的总长
        seekbarVideo.setMax(duration);

        //设置视频的总时间
        tvDuration.setText(utils.stringForTime(duration));

        //发消息
        handler.sendEmptyMessage(PROGRESS);

    }
}
(3)处理handler发送的消息
 private Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        switch (msg.what) {
            case PROGRESS:
                //1.得到当前的视频播放进程
                int currentPosition = videoView.getCurrentPosition();//0

                //2.SeekBar.setProgress(当前进度);
                seekbarVideo.setProgress(currentPosition);

                //3.更新文本播放进度
                tvCurrentTime.setText(utils.stringForTime(currentPosition));

                //此处需要设置系统时间,下面介绍
                tvSystemTime.setText(getSysteTime());

                //4.每秒更新一次
                handler.removeMessages(PROGRESS);
                handler.sendEmptyMessageDelayed(PROGRESS, 1000);
                break;
        }
    }
};

3、播放视频进度条SeekBar拖拽事件

(1)为SeekBar设置监听
//设置视频播放SeeKbar状态变化的监听
seekbarVideo.setOnSeekBarChangeListener(new VideoOnSeekBarChangeListener());
(2)监听器实现
 class VideoOnSeekBarChangeListener implements SeekBar.OnSeekBarChangeListener {

    /**
     * 当手指滑动的时候,会引起SeekBar进度变化,会回调这个方法
     * @param seekBar
     * @param progress
     * @param fromUser 如果是用户引起的true,不是用户引起的false
     */
    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        if (fromUser) {
            videoview.seekTo(progress);
        }
    }

    /**
     * 当手指触碰的时候回调这个方法
     * @param seekBar
     */
    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {

    }

    /**
     * 当手指离开的时候回调这个方法
     * @param seekBar
     */
    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {

    }
}

4、音量进度条SeekBar的监听

(1)、在OnCreate()方法中,初始化AudioManager,并将SeekBar与最大音量相关联
//得到音量
am = (AudioManager) getSystemService(AUDIO_SERVICE);
currentVoice = am.getStreamVolume(AudioManager.STREAM_MUSIC);
maxVoice = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
//最大音量和SeekBar关联
seekbarVoice.setMax(maxVoice);
//设置当前进度-当前音量
seekbarVoice.setProgress(currentVoice);
(2)、为音量SeekBar设置监听
//为音量SeekBar设置监听
seekbarVoice.setOnSeekBarChangeListener(new VoiceOnSeekBarChangeListener());
(3)、监听器
 class VoiceOnSeekBarChangeListener implements SeekBar.OnSeekBarChangeListener {

    //该参数同上述SeekBar
    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        if (fromUser) {
            if (progress > 0) {
                isMute = false;
            } else {
                isMute = true;
            }
            updataVoice(progress, isMute);
        }

    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {

    }

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {

    }
}

    /**
     * 设置音量的大小
     * @param progress
     */
    private void updataVoice(int progress, boolean isMute) {
        if (isMute) {
            am.setStreamVolume(AudioManager.STREAM_MUSIC, 0, 0);
            seekbarVoice.setProgress(0);
        } else {
            am.setStreamVolume(AudioManager.STREAM_MUSIC, progress, 0);
            seekbarVoice.setProgress(progress);
            currentVoice = progress;
        }
    }
(4)、将音量与实体按键相关联
/**
     * 监听物理健,实现声音的调节大小
     *
     * @param keyCode
     * @param event
     * @return
     */
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
            currentVoice--;
            updataVoice(currentVoice, false);
            return true;
        } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
            currentVoice++;
            updataVoice(currentVoice, false);
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

5、效果图,见图一

三、注册监听手机电量的广播接收器和获取系统时间

1、注册监听手机电量的广播接收器

(1)在onCreate()生命周期方法内,注册监听电量的广播接收器
//此处为全局变量,因为要解除绑定
receiver = new MyReceiver();
IntentFilter intentFiler = new IntentFilter();
//当电量变化的时候发这个广播
intentFiler.addAction(Intent.ACTION_BATTERY_CHANGED);
registerReceiver(receiver, intentFiler);
(2)、定义广播接收器
class MyReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        int level = intent.getIntExtra("level", 0);//0~100;
        //不同的值,设置不同的图片
        if (level <= 0) {
            ivBattery.setImageResource(R.drawable.ic_battery_0);
        } else if (level <= 10) {
            ivBattery.setImageResource(R.drawable.ic_battery_10);
        } else if (level <= 20) {
            ivBattery.setImageResource(R.drawable.ic_battery_20);
        } else if (level <= 40) {
            ivBattery.setImageResource(R.drawable.ic_battery_40);
        } else if (level <= 60) {
            ivBattery.setImageResource(R.drawable.ic_battery_60);
        } else if (level <= 80) {
            ivBattery.setImageResource(R.drawable.ic_battery_80);
        } else if (level <= 100) {
            ivBattery.setImageResource(R.drawable.ic_battery_100);
        } else {
            ivBattery.setImageResource(R.drawable.ic_battery_100);
        }
    }
}
3、需要在onDestroy()方法内部,解除广播接收器
@Override
protected void onDestroy() {

    //释放资源的时候,先释放子类,在释放父类
    if (receiver != null) {
        unregisterReceiver(receiver);
        receiver = null;
    }
    super.onDestroy();
}

2、获取系统的时间

(1)、得到系统时间
public String getSysteTime() {
    SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
    return format.format(new Date());
}
(2)、,在handler中,设置系统时间
//设置系统时间(上面注释掉)
tvSystemTime.setText(getSysteTime());

3、见图二

四、效果

1、图一

这里写图片描述
2、图二
这里写图片描述



五、补充

1、手指上下滑动屏幕,来调节音量的高低

步骤:

(1)、获取屏幕的高和宽:
    screenHeight;     //屏幕的高
    screenWidth;      //屏幕的宽

(2)、计算滑动的上下距离;
        //往下滑动
        float distanceY = startY - endY  < 0;
        //往上滑动
        float distanceY = startY - endY > 0;

 (3)、利用公式,计算改变的声音;
        //公式:滑动屏幕的距离: 总距离 = 改变声音:音量最大值

        改变声音 = (滑动屏幕的距离 :总距离)* 音量最大值

(4)、得到最终声音;
        最终声音 = 原来的声音 + 改变声音;

2、在事件中,得到需要的变量值

(1)、onTouchEvent事件方法里,在按下(down)的时候得到:
    startY      //开始位置
    totalDis    //屏幕的总距离
    cVol        //当前音量
(2)、onTouchEvent事件方法里,在移动(move)的时候得到:
    float endY =  envent.getY();                       //得到结束位置
    float distanceY = endY - startY;                   //得到计算距离
    改变声音 = (滑动屏幕的距离 :总距离)* 音量最大值     //得到改变的音量
    最终声音 = cVol + 改变声音;
    updataVoice();                                     //设置音量

3、具体代码

//得到屏幕的宽和高方式
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
screenWidth = displayMetrics.widthPixels;
screenHeight = displayMetrics.heightPixels;

private float startY;
private float totalDis;  //屏幕的高(总距离)
private int cVol;        //一触碰屏幕时的当前音量

@Override
public boolean onTouchEvent(MotionEvent event) {

    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN://手指按下

            //1.按下记录值
            startY = event.getY();
            cVol = am.getStreamVolume(AudioManager.STREAM_MUSIC);
            totalDis= Math.min(screenHeight, screenWidth);
            break;

        case MotionEvent.ACTION_MOVE://手指移动
            float endY = event.getY();
            float distanceY = startY - endY;

            //改变声音 = (滑动屏幕的距离: 总距离)*音量最大值
            float delta = (distanceY / totalDis) * maxVoice;

            //最终声音 = 原来的 + 改变声音;
            int voice = (int) Math.min(Math.max(cVol + delta, 0), maxVoice);
            if (delta != 0) {
                isMute = false;
                updataVoice(voice, isMute);
            }
            break;

        case MotionEvent.ACTION_UP://手指离开

            break;
    }
    return super.onTouchEvent(event);
}

猜你喜欢

转载自blog.csdn.net/zxd1435513775/article/details/81535065