播放器常用手势操控封装GestureView

一、播放器常用手势操控包括:

1、单击显示和隐藏播放器控件;

2、双击播放暂停;

3、左侧上下滑动调节亮度;

4、右侧上下滑动调节音量;

5、左右滑动调节进度。

 

二、手势检测帮助类PlayerGestureHelper。

用于检测区分手势类型。代码如下:

package com.dway.gesture;

import android.content.Context;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ViewConfiguration;

/**
 * 播放器常用手势监听:单击、双击、横向滑动、左右两侧纵向滑动(亮度和声音)
 */

public class PlayerGestureHelper extends GestureDetector.SimpleOnGestureListener {

    private OnPlayerGestureListener mListener;
    //播放器View的长宽
    private float mPlayerWidth;
    private float mPlayerHeight;
    private GestureMode mGestureMode = GestureMode.NONE;
    private int mTouchSlop;

    public PlayerGestureHelper(Context context, OnPlayerGestureListener listener) {
        this.mListener = listener;
        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
    }

    public void setPlayerSize(float width, float height){
        mPlayerWidth = width;
        mPlayerHeight = height;
    }

    public GestureMode getGestureMode() {
        return mGestureMode;
    }

    @Override
    public boolean onDown(MotionEvent e) {
        mGestureMode = GestureMode.NONE;
        if (mListener != null) {
            mListener.onDown(e);
        }
        return true;
    }

    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        return super.onSingleTapUp(e);
    }

    @Override
    public void onShowPress(MotionEvent e) {
        super.onShowPress(e);
    }

    @Override
    public void onLongPress(MotionEvent e) {
        super.onLongPress(e);
    }

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        if (mGestureMode == GestureMode.NONE) {
            if (Math.abs(distanceX) > mTouchSlop) {//横向滑动
                mGestureMode = GestureMode.PROGRESS;
            } else if (Math.abs(distanceY) > mTouchSlop) {//纵向滑动
                if (e1.getX() < mPlayerWidth/2) {
                    mGestureMode = GestureMode.BRIGHTNESS;
                } else {
                    mGestureMode = GestureMode.VOLUME;
                }
            }
        } else if (mGestureMode == GestureMode.PROGRESS) {//快进快退
            if (mListener != null) {
                mListener.onGestureProgress(e1, e2, distanceX, distanceY);
            }
        } else if (mGestureMode == GestureMode.BRIGHTNESS) {
            if (mListener != null) {
                mListener.onGestureBrightness(e1, e2, distanceX, distanceY);
            }
        } else if (mGestureMode == GestureMode.VOLUME) {
            if (mListener != null) {
                mListener.onGestureVolume(e1, e2, distanceX, distanceY);
            }
        }
        return true;
    }

    @Override
    public boolean onDoubleTap(MotionEvent e) {
        if (mListener != null) {
            mListener.onGestureDoubleTap(e);
        }
        return super.onDoubleTap(e);
    }

    @Override
    public boolean onDoubleTapEvent(MotionEvent e) {
        return super.onDoubleTapEvent(e);
    }

    @Override
    public boolean onSingleTapConfirmed(MotionEvent e) {
        if (mListener != null) {
            mListener.onGestureSingleTap(e);
        }
        //单击事件,在双击事件发生时不会产生这个事件,所以用这个回调作为播放器单击事件
        return super.onSingleTapConfirmed(e);
    }

    public interface OnPlayerGestureListener {
        //亮度手势,手指在左侧上下滑动
        void onGestureBrightness(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);

        //音量手势,手指在右侧上下滑动
        void onGestureVolume(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);

        //进度手势,手指左右滑动
        void onGestureProgress(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);

        //单击手势
        void onGestureSingleTap(MotionEvent e);

        //双击手势
        void onGestureDoubleTap(MotionEvent e);

        //按下手势
        void onDown(MotionEvent e);
    }

    /**
     * 手势类型
     */
    public enum GestureMode {
        NONE,               //默认值
        BRIGHTNESS,         //左侧上下滑动(亮度调节)
        VOLUME,             //右侧上下滑动(声音调节)
        PROGRESS,           //横向滑动(进度调节)
    }
}

 

三、GestureView说明

GestureView继承于View,使用时直接放在播放器上层即可,该View内部封装了自动调节亮度和音量的功能,对外只保留必要的接口。代码如下:

package com.dway.gesture;

import android.app.Service;
import android.content.Context;
import android.media.AudioManager;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;

/**
 * 手势操控View
 */
public class GestureView extends View implements View.OnTouchListener {

    private boolean mGestureEnable = true;
    private PlayerGestureHelper mGestureHelper;
    private GestureDetector mGestureDetector;
    private GestureListener mGestureListener;
    private AudioManager mAudioManager;
    private int mMaxVolume = 0;
    private int mOldVolume = 0;
    private float mOldBrightness = 0;
    private Window mWindow;
    private int mDuration = 0;
    private int mOldProgress = 0;
    private int mNewProgress = 0;

    public GestureView(Context context) {
        super(context);
        init();
    }

    public GestureView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public GestureView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init(){
        mGestureHelper = new PlayerGestureHelper(getContext(), new MyPlayerGestureListener());
        mGestureDetector = new GestureDetector(getContext(), mGestureHelper);
        post(new Runnable() {
            @Override
            public void run() {
                mGestureHelper.setPlayerSize(getWidth(), getHeight());
            }
        });
        setOnTouchListener(this);
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if(mGestureEnable) {
            if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) {
                PlayerGestureHelper.GestureMode gestureMode = mGestureHelper.getGestureMode();
                if (gestureMode == PlayerGestureHelper.GestureMode.PROGRESS) {
                    //手势检测的seekTo操作,因为GestureDetector不能检测手势抬起
                   if(mGestureListener != null){
                       mGestureListener.onGestureProgressUp(mNewProgress, mDuration);
                   }
                }
                if(gestureMode == PlayerGestureHelper.GestureMode.PROGRESS
                        || gestureMode == PlayerGestureHelper.GestureMode.BRIGHTNESS
                        || gestureMode == PlayerGestureHelper.GestureMode.VOLUME) {
                    if (mGestureListener != null) {
                        mGestureListener.onScrollGestureEnd();
                    }
                }
            }
            return mGestureDetector.onTouchEvent(event);
        }else {
            return false;
        }
    }

    public void setGestureEnable(boolean gestureEnable){
        mGestureEnable = gestureEnable;
    }

    public void setGestureListener(GestureListener gestureListener){
        mGestureListener = gestureListener;
    }


    class MyPlayerGestureListener implements PlayerGestureHelper.OnPlayerGestureListener {

        @Override
        public void onGestureBrightness(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            if(mGestureEnable){
                if (mGestureListener != null) {
                    float offset = e1.getY() - e2.getY();
                    float brightness = mOldBrightness + 2 * offset / getHeight();
                    if(brightness < 0){
                        brightness = 0;
                    }else if(brightness > 1){
                        brightness = 1;
                    }
                    if(mWindow != null){
                        WindowManager.LayoutParams lp = mWindow.getAttributes();
                        lp.screenBrightness = brightness;
                        mWindow.setAttributes(lp);
                    }
                    mGestureListener.onGestureBrightness(brightness);
                }
            }
        }

        @Override
        public void onGestureVolume(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            if(mGestureEnable){
                if (mGestureListener != null) {
                    float offset = e1.getY() - e2.getY();
                    int volume = (int) (mOldVolume + mMaxVolume * 2 * offset / getHeight());
                    if(volume < 0){
                        volume = 0;
                    }else if(volume > mMaxVolume){
                        volume = mMaxVolume;
                    }
                    mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, AudioManager.FLAG_PLAY_SOUND);
                    mGestureListener.onGestureVolume(volume, mMaxVolume);
                }
            }
        }

        @Override
        public void onGestureProgress(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            if(mGestureEnable) {
                if (mGestureListener != null) {
                    if(mDuration == 0){
                        mDuration = mGestureListener.getDuration();
                    }
                    float offset = e2.getX() - e1.getX();
                    // 视频时长为1小时以上,小屏和全屏的手势滑动最长为视频时长的十分之一
                    if (mDuration >= 60 * 60 * 1000) {
                        mNewProgress = (int) (mOldProgress + offset / getWidth() * mDuration / 10);
                    }// 视频时长为31分钟-60分钟时,小屏和全屏的手势滑动最长为视频时长五分之一
                    else if (mDuration >= 30 * 60 * 1000) {
                        mNewProgress = (int) (mOldProgress + offset / getWidth() * mDuration / 5);
                    }// 视频时长为11分钟-30分钟时,小屏和全屏的手势滑动最长为视频时长三分之一
                    else if (mDuration >= 10 * 60 * 1000) {
                        mNewProgress = (int) (mOldProgress + offset / getWidth() * mDuration / 3);
                    }// 视频时长为4-10分钟时,小屏和全屏的手势滑动最长为视频时长二分之一
                    else if (mDuration >= 3 * 60 * 1000) {
                        mNewProgress = (int) (mOldProgress + offset / getWidth() * mDuration / 2);
                    }// 视频时长为1秒钟至3分钟时,小屏和全屏的手势滑动最长为视频结束
                    else {
                        mNewProgress = (int) (mOldProgress + offset / getWidth() * mDuration);
                    }
                    if (mNewProgress > mDuration) {
                        mNewProgress = mDuration;
                    } else if (mNewProgress < 0) {
                        mNewProgress = 0;
                    }
                    mGestureListener.onGestureProgress(mNewProgress, mDuration);
                }
            }
        }

        @Override
        public void onGestureSingleTap(MotionEvent e) {
            if(mGestureEnable) {
                if (mGestureListener != null) {
                    mGestureListener.onGestureSingleTap();
                }
            }
        }

        @Override
        public void onGestureDoubleTap(MotionEvent e) {
            if(mGestureEnable) {
                if (mGestureListener != null) {
                    mGestureListener.onGestureDoubleTap();
                }
            }
        }

        @Override
        public void onDown(MotionEvent e) {
            if(mGestureEnable){
                if(mGestureListener != null) {
                    mDuration = mGestureListener.getDuration();
                    mOldProgress = mGestureListener.getCurrent();
                    mAudioManager = (AudioManager) getContext().getSystemService(Service.AUDIO_SERVICE);
                    mMaxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
                    mOldVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
                    mWindow = mGestureListener.getActivityWindow();
                    if (mWindow != null) {
                        WindowManager.LayoutParams layoutParams = mWindow.getAttributes();
                        mOldBrightness = layoutParams.screenBrightness;
                        if (mOldBrightness == WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE) {
                            mOldBrightness = 0.5f;
                        }
                    }
                    mGestureListener.onDown();
                }
            }
        }
    }


    public interface GestureListener{

        /**
         * 亮度调节回调
         * @param brightness [0, 1]
         */
        void onGestureBrightness(float brightness);

        /**
         * 音量调节回调
         * @param volume 当前音量
         * @param MaxVolume 最大音量
         */
        void onGestureVolume(int volume, int MaxVolume);

        /**
         * 进度调节
         * @param progress 进度
         * @param duration 总长度
         */
        void onGestureProgress(int progress, int duration);

        /**
         * 进度调节后抬起动作,需要对播放器进行seekTo操作
         * @param progress 进度
         * @param duration 总长度
         */
        void onGestureProgressUp(int progress, int duration);

        /**
         * 单击
         */
        void onGestureSingleTap();

        /**
         * 双击
         */
        void onGestureDoubleTap();

        /**
         * 按下
         */
        void onDown();

        /**
         * 滑动手势结束(即进度、音量、亮度调节手势结束)
         */
        void onScrollGestureEnd();

        /**
         * 获取当前播放进度
         * @return
         */
        int getCurrent();

        /**
         * 获取总长度
         * @return
         */
        int getDuration();

        /**
         * 获取Activity的Window,作为调节亮度用
         * @return
         */
        Window getActivityWindow();
    }

}

 

四、如何使用

1、直接将GestureView置于播放器布局上层。

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:splitMotionEvents="false">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:background="#000000">
        <SurfaceView
            android:id="@+id/player_surface"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>

    <com.dway.gesture.GestureView
        android:id="@+id/player_gestureview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="visible"/>

</FrameLayout>

2、在Activity中使用如下:

//需要打开手势功能则调用该方法,并处理相关手势接口
private void enableGesture(){
    GestureView gestureView = findViewById(R.id.player_gestureview);
    gestureView.setVisibility(VISIBLE);
    gestureView.setGestureEnable(true);
    gestureView.setGestureListener(new MyGestureListener());
}

//需要关闭手势功能则调用该方法
private void disableGesture(){
    GestureView gestureView = findViewById(R.id.player_gestureview);
    gestureView.setVisibility(GONE);
    gestureView.setGestureEnable(false);
}

//手势回调处理,其中需要传当前播放进度和视频总长度,Activity的window也需要传进去
class MyGestureListener implements GestureView.GestureListener{

        @Override
        public void onGestureBrightness(float brightness) {
            //此处可以显示亮度调节
        }

        @Override
        public void onGestureVolume(int volume, int MaxVolume) {
            //此处可以显示音量调节
        }

        @Override
        public void onGestureProgress(int progress, int duration) {
            //此处可以显示进度调节
        }

        @Override
        public void onGestureProgressUp(int progress, int duration) {
            //此处可以进行播放器的seekTo操作
        }

        @Override
        public void onGestureSingleTap() {
            //单击,可以显示和隐藏播放器上下的控件等
        }

        @Override
        public void onGestureDoubleTap() {
            //双击,可以进行播放暂停操作
        }

        @Override
        public void onDown() {

        }

        @Override
        public void onScrollGestureEnd() {
            //亮度、音量或进度调节手势结束,可以隐藏调节过程的相关UI
        }

        @Override
        public int getCurrent() {
            return mPlayer != null ? (int) mPlayer.getCurrentPosition() : 0;
        }

        @Override
        public int getDuration() {
            return mPlayer != null ? (int) mPlayer.getDuration() : 0;
        }

        @Override
        public Window getActivityWindow() {
            return getWindow();
        }
    }

 

通过封装,使用代码就很简洁了,只需要处理相关提示的UI即可,至于怎么调节亮度和音量等则不需要考虑了。

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值