播放器常用手勢操控封裝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即可,至於怎麼調節亮度和音量等則不需要考慮了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章