OnTouchListener

直接上代码  使用     单击 双击 长按 根据坐标点角度判断滑动方向

constraintLayout = findViewById(R.id.constraintLayout);

constraintLayout.setOnTouchListener(new BaseOnTouchListener2());


package com.sharkz.tool.OnTouch;

import android.os.Handler;

import android.os.Looper;

import android.util.Log;

import android.view.MotionEvent;

import android.view.View;

/**

* ================================================

* 作    者:SharkZ

* 邮    箱:[email protected]

* 创建日期:2020-01-09  14:58

* 描    述

* 修订历史:

* ================================================

*/

public abstract class BaseOnTouchListener2implements View.OnTouchListener {

private static StringTAG ="BaseOnTouchListener2";

    /**

* 长按事件的时间判断条件 600ms

*/

    private static final long LONG_CLICK_LIMIT =800;

    /**

* 单击事件判断条件

*/

    private static final long SHORT_CLICK_LIMIT =400;

    /**

* 双击事件 判断时间

*/

    private static final long DOUBLE_CLICK_LIMIT =300;

    /**

* 滑动事件 最小判断标示

*/

    private static final int MOVE_BOUNDARY =80;

    /**

* 点击事件

*/

    private boolean mIsClick;

    /**

* 长按事件

*/

    private boolean mIsLongClick;

    /**

* 双击事件 用于点击事件之间的判断

*/

    private boolean mIsDoubleClick;

    /**

* 当前正在执行长按操作 用于和滑动事件之间的判断

*/

    private boolean onLongClick;

    /**

* 第一次点击的时间戳 / 全部手指离开屏幕的时间戳

*/

    private long downCurrentTimeMillis =0;

    private long upCurrentTimeMillis =0;

    /**

* 触摸的是坐标区域还是右边区域 --> 当前将屏幕分成 左右两个区域

*/

    private boolean mIsLeftArea;

    private boolean mIsRightArea;

    /**

* 左边区域/右边区域

*/

    private static final int AREA_LEFT =0;

    private static final int AREA_RIGHT =1;

    /**

* 滑动的距离

*/

    private int mMoveX;

    private int mMoveY;

    /**

* 第一个触点坐标

*/

    private int mFirstX, mFirstY;

    /**

* 实时坐标点

*/

    private int x, y;

    /**

* 滑动方向

*/

    private boolean mIsXMove;

    private boolean mIsYMove;

    /**

* 双指操作

*/

    private boolean doublePointMove =false;

    /**

* 两个手指之间的距离

*/

    private double distance =0;

    // =============================================================================================

    /**

* 用于手势判断的 条件

*

    * @param basePlayManager

    */

    private boolean basePlayManager;

    public void setBasePlayManager(boolean basePlayManager) {

this.basePlayManager = basePlayManager;

    }

/**

* 事件处理

*/

    private HandlermHandler =new Handler(Looper.getMainLooper());

    // =============================================================================================

    @Override

    public boolean onTouch(View v, MotionEvent event) {

// 当前 触摸点坐标

        x = (int) event.getX();

        y = (int) event.getY();

        // 触摸设备时手指的数量

        int pCount = event.getPointerCount();

        // 热区在这里判断 触摸点在热区 直接返回

        if (isInHotspot(v, event)) {

event.setAction(MotionEvent.ACTION_CANCEL);

            Log.i(TAG, "onTouch: 热区在这里判断 触摸点在热区 直接返回");

        }

// 手势类型

        int action = event.getAction();

        switch (action) {

// 用户第一次 触摸

            case MotionEvent.ACTION_DOWN:

actionDown(v, event);

break;

            // 滑动

            case MotionEvent.ACTION_MOVE:

// 如果当前是长按事件 --> 取消 滑动操作

                if (onLongClick) {

break;

                }

if (pCount ==1) {

actionMove();

                }

if (pCount ==2) {

actionDoublePointMove(event);

                }

break;

            case MotionEvent.ACTION_UP:

actionUp();

break;

            case MotionEvent.ACTION_CANCEL:

actionCancel();

break;

        }

return true; // 默认处理当前事件

    }

// =============================================================================================

    /**

* 两指操作

*

    * @param event

    */

    private void actionDoublePointMove(MotionEvent event) {

doublePointMove =true;

        mIsClick =false; // 取消单击操作

        mIsLongClick =false;// 取消长按事件

        mIsDoubleClick =false; // 取消双击事件

// 如果当前是 滑动操作 --> 取消长按事件

        mHandler.removeCallbacks(longClickRn);

        // Log.i(TAG, "onTouch: 两指操作");

//Log.i(TAG, "actionDoublePointMove: distance==" + distance);

        if (distance ==0) {

distance = distanceBetweenFingers(event);

        }else{

if (distance > distanceBetweenFingers(event)) {

onNarrow();

            }else {

onEnLarge();

            }

}

}

/**

* ACTION MOVE 事件处理

*/

    private void actionMove() {

if (doublePointMove) {

return;

        }

mMoveX =x -mFirstX;

        mMoveY =mFirstY -y;

        // 坐标点夹脚

        int an = -1;

        // 判断点击、长按/滑动 满足下面的条件就是滑动事件了

        if (Math.abs(mMoveY) >MOVE_BOUNDARY || Math.abs(mMoveX) >MOVE_BOUNDARY) {

mIsClick =false; // 取消单击操作

            mIsLongClick =false;// 取消长按事件

            mIsDoubleClick =false; // 取消双击事件

// 如果当前是 滑动操作 --> 取消长按事件

            mHandler.removeCallbacks(longClickRn);

            // 夹脚

            an = angle(mFirstX, mFirstY, x, y);

        }

// 判断操作状态

        if (!mIsXMove && !mIsYMove) {

if (Math.abs(mMoveY) >MOVE_BOUNDARY && an <90 && an >45) {

mIsYMove =true;

                mIsXMove =false;

                mIsDoubleClick =false; // 取消双击事件

            }

if (Math.abs(mMoveX) >MOVE_BOUNDARY && an <45 && an >0) {

mIsXMove =true;

                mIsYMove =false;

                mIsDoubleClick =false; // 取消双击事件

            }

}

// X轴滑动 改变播放进度

        if (mIsXMove) {

onXMove(mMoveX);

        }

// Y轴滑动

        if (mIsYMove) {

if (mIsLeftArea) {

onYMove(AREA_LEFT, mMoveY);

            }else {

onYMove(AREA_RIGHT, mMoveY);

            }

}

}

/**

* ACTION DOWN 事件处理

*

    * @param v

    * @param event

    */

    private void actionDown(View v, MotionEvent event) {

// 记录下当前的时间戳

        downCurrentTimeMillis = System.currentTimeMillis();

        // 重置单击和长按的定时器

        mHandler.removeCallbacks(onCLickRn);

        mHandler.removeCallbacks(longClickRn);

        // 初始化变量

        int controlAreaWidth = v.getWidth() /2;

        mFirstX = (int) event.getX();

        mFirstY = (int) event.getY();

        // 判断触控区域是左还是右

        mIsLeftArea =mFirstX < controlAreaWidth;

        mIsRightArea =mFirstX > v.getWidth() - controlAreaWidth;

        // 点击事件 down 的时候 丧钟方式都开启了

        mIsClick =true;

        mIsLongClick =true;

        mIsDoubleClick =true;

        // 长按延时执行 --> up的时候取消

        mHandler.postDelayed(longClickRn, LONG_CLICK_LIMIT);

    }

/**

* ACTION UP 事件处理

* 最后一根手指离开屏幕

*/

    private void actionUp() {

// 双击事件处理

        if (downCurrentTimeMillis -upCurrentTimeMillis

mIsClick =false; // 取消单击事件

            mIsLongClick =false; // 取消长按事件

            mHandler.removeCallbacks(longClickRn); // 长按定时器

            mHandler.removeCallbacks(onCLickRn); // 单击定时器

            onDoubleClick();

        }

// 记录一下 最后一个手指离开屏幕的时间戳

        upCurrentTimeMillis = System.currentTimeMillis();

        // 处理长按

        cancelLongClick();

        // 处理单击

        mHandler.postDelayed(onCLickRn, SHORT_CLICK_LIMIT);

        // 下面是滑动 重置处理

        if (mIsXMove) {

onXMoveEnd(mMoveX);

        }

if (mIsYMove) {

if (mIsLeftArea) {

onYMoveEnd(AREA_LEFT, mMoveY);

            }else {

onYMoveEnd(AREA_RIGHT, mMoveY);

            }

}

// 滑动事件重置

        mIsXMove =false;

        mIsYMove =false;

        // 双指操作

        doublePointMove =false;

        distance =0;

    }

/**

* ACTION CANCEL 事件处理

* 从表象来说明就是:当触摸事件从我们的控件开始,也就是ACTION_DOWN被我们返回true处理,

* 然后手指移动到当前控件的外面,这时候就会触发ACTION_CANCLE事件,

* 触发cancle事件就不会接收到up事件!!! 实际上当手指移动到了当前控件之外的时候,

* 这个触摸事件被他的父控件拦截掉了,所以触发了cancle事件.之后的触摸事件就再也不会传递到当前控件的onTouchEvent里面.

*/

    private void actionCancel() {

// 滑动事件重置

        mIsXMove =false;

        mIsYMove =false;

    }

/**

* 两个坐标点与 X轴的夹脚

* 根据需求 夹脚45度以内 X轴

* 夹脚45度以上 Y轴

*

    * @param x1 x1

    * @param y1 y1

    * @param x2 x2

    * @param y2 y2

    * @return 两个坐标点连线与X轴的夹脚

*/

    private int angle(int x1, int y1, int x2, int y2) {

int x = Math.abs(x1 - x2);

        int y = Math.abs(y1 - y2);

        double z = Math.sqrt(x * x + y * y);

        return Math.round((float) (Math.asin(y / z) / Math.PI *180));//最终角度

    }

/**

* 计算两个手指之间的距离。

*

    * @param event

    * @return 两个手指之间的距离

*/

    private double distanceBetweenFingers(MotionEvent event) {

float disX = Math.abs(event.getX(0) - event.getX(1));

        float disY = Math.abs(event.getY(0) - event.getY(1));

        return Math.sqrt(disX * disX + disY * disY);

    }

// =============================================================================================

    /**

* 单击计时器

*/

    private RunnableonCLickRn =new Runnable() {

@Override

        public void run() {

if (mIsClick &&upCurrentTimeMillis -downCurrentTimeMillis

mHandler.removeCallbacks(longClickRn);

                onClick();

            }

}

};

    /**

* 长按事件计时器

*/

    private RunnablelongClickRn =new Runnable() {

@Override

        public void run() {

if (mIsLongClick) {

mIsDoubleClick =false;

                onLongClick =true;

                onLongClick();

            }

}

};

    /**

* 取消长按事件

*/

    private void cancelLongClick() {

// 判断事件戳 是否大于 600;

        if (mIsLongClick &&upCurrentTimeMillis -downCurrentTimeMillis >600) {

mIsDoubleClick =false;

            mHandler.removeCallbacks(onCLickRn);

            onLongClick =false;

            onLongClickEnd();

        }

// 重置判断标识条件

        mIsLongClick =false;

    }

// =============================================================================================

    /**

* 长按

*/

    public void onLongClick() {

Log.i(TAG, "onLongClick: 触发长按事件");

    }

/**

* 长按结束

*/

    public void onLongClickEnd() {

Log.i(TAG, "onLongClickEnd: 长按结束");

    }

/**

* 点击

*/

    public void onClick() {

Log.i(TAG, "onClick: 单击事件");

    }

/**

* 双击

*/

    public void onDoubleClick() {

Log.i(TAG, "onDoubleClick: 双击事件");

    }

/**

* X轴方向滑动

*

    * @param size 滑动距离

*/

    public void onXMove(int size) {

Log.i(TAG, "onXMove: X轴方向滑动 -->" + size);

    }

/**

* X轴方向滑动

*

    * @param area 左边/右边

    * @param size 滑动距离

*/

    public void onYMove(int area, int size) {

String ar ="左边区域";

        if (area ==AREA_RIGHT) {

ar ="右边区域";

        }

Log.i(TAG, "onXMove: Y轴方向滑动 --> " + ar + size);

    }

/**

* X轴方向滑动结束

*

    * @param size 滑动距离

*/

    public void onXMoveEnd(int size) {

Log.i(TAG, "onXMoveEnd: X轴方向滑动结束 " + size);

    }

/**

* Y轴方向滑动结束

*

    * @param area 左边/右边

    * @param size 滑动距离

*/

    public void onYMoveEnd(int area, int size) {

Log.i(TAG, "onYMoveEnd: Y轴方向滑动结束" + size);

    }

/**

* 当前触点坐标是否在热区里面  --> 这个给子类去实现

*

    * @param v

    * @param event

    * @return

    */

    public boolean isInHotspot(View v, MotionEvent event) {

boolean isInHotspot =false;

        int y = (int) event.getY();

        if (y >600) {

isInHotspot =true;

        }

return isInHotspot;

    }

/**

* 双指放大

*/

    public void onEnLarge() {

Log.i(TAG, "onEnLarge: 双指放大");

    }

/**

* 双指缩小

*/

    public void onNarrow() {

Log.i(TAG, "onNarrow: 双指缩小");

    }

}

你可能感兴趣的:(OnTouchListener)