安卓开发-----手势动作

在某个point我是非常需要像百度地图那些自定义手势动作,能够放大,缩小,移动,旋转,但是在网上却找不到一个立马下载能使用的包,不说那么多,我先上接口代码:

import android.view.MotionEvent;

/**
 * Created by mr.Hao on 20**/**/**.
 */

public interface OnGestuerListner {
    public boolean onOneTouch(MotionEvent event);//点击一个点

    public void onTranslate(float x, float y);//手指移动,有正负值,直接累加即可

    public void onLarge(float px, float centerX, float centerY);//放大手势 ,相差多少,中心点坐标

    public void onDecrease(float px, float centerX, float centerY);//缩小手势,相差多少,中心点坐标

    public void onRotate(float degree, float centerX, float centerY);//旋转手势,中心点

    public void onDoubleClick();//双击
}

看到接口怎么样?感觉流口水了吧?,那么我们继续上实现的代码:

import android.util.Log;
import android.view.MotionEvent;

/**
 * Created by mr.Hao on 20**/**/**.
 */
public class GestuerControl {
    private OnGestuerListner listener;

    public GestuerControl(OnGestuerListner listener) {
        this.listener = listener;
    }

    //移动
    float mX;//移动的x轴
    float mY;//移动的y轴
    //是否在放大手势
    private boolean isScale = false;
    //放大的距离
    float distance = 0;


    public boolean OnEvent(MotionEvent event) {
        if (this.listener == null) {
            return false;
        }
        //现获得触摸点数量
        int pointerCount = event.getPointerCount();
        if (pointerCount == 1) {
            //判断是否在放大手势,因为放大手势最后会remove
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    isScale = false;
                    mX = event.getX();
                    mY = event.getY();
                    return this.listener.onOneTouch(event);
                case MotionEvent.ACTION_MOVE:
                    if (!isScale) {
                        //移动了多少个像素
                        float difX = Math.abs(mX - event.getX());
                        float difY = Math.abs(mY - event.getY());
                        if (mX < event.getX() && mY == event.getY()) {
                            //向右
                            listener.onTranslate(difX, 0);
                        } else if (mX > event.getX() && mY == event.getY()) {
                            //向左
                            listener.onTranslate(-difX, 0);
                        } else if (mY < event.getY() && mX == event.getX()) {
                            //向下
                            listener.onTranslate(0, difY);
                        } else if (mY > event.getY() && mX == event.getX()) {
                            //向上
                            listener.onTranslate(0, -difY);
                            //共同移动
                        } else if (mX < event.getX() && mY < event.getY()) {
                            //向右,向下
                            listener.onTranslate(difX, difY);
                        } else if (mX < event.getX() && mY > event.getY()) {
                            //向右,向上
                            listener.onTranslate(difX, -difY);
                        } else if (mX > event.getX() && mY < event.getY()) {
                            //向左,向下
                            listener.onTranslate(-difX, difY);
                        } else if (mX > event.getX() && mY > event.getY()) {
                            //向左,向下
                            listener.onTranslate(-difX, -difY);
                        }
                        mX = event.getX();
                        mY = event.getY();
                        return this.listener.onOneTouch(event);
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    distance = 0;
                    lastX1 = -1;
                    lastY1 = -1;
                    lastX2 = -1;
                    lastY2 = -1;
                    //开始判断是否是双击
                    long clickTime = System.currentTimeMillis();
                    //判断范围
                    float clickX = event.getX();
                    float clickY = event.getY();
                    //先判断点击范围
                    if (Math.abs(clickX - lastClickX) < ENABLE_CLICK_DIS && Math.abs(clickY - lastClickY) < ENABLE_CLICK_DIS) {
                        //判断点击时间
                        if ((clickTime - lastClickTime) < DOUBLE_CLICK_TIME) {
                            listener.onDoubleClick();
                            //双击后复原,防止多重点击
                            lastClickTime = 0;
                            lastClickX = 0f;
                            lastClickY = 0f;
                        } else {
                            //如果是第一次点击就赋值
                            lastClickTime = clickTime;
                        }
                    } else {
                        lastClickX = clickX;
                        lastClickY = clickY;
                        lastClickTime = clickTime;
                    }
                    break;
            }
        } else if (pointerCount > 1) {
            onTwoTouch(event);
        }
        return true;
    }

    //最后点击的位置
    private float lastClickX = 0f;
    private float lastClickY = 0f;
    //在这个点击返回内判断是点击有效
    private final static float ENABLE_CLICK_DIS = 50;

    //最后点击的时间
    private long lastClickTime = 0;
    //当两次点击小于这个时间被认为是双击
    private final static long DOUBLE_CLICK_TIME = 500;


    private float lastX1 = -1;
    private float lastY1 = -1;
    private float lastX2 = -1;
    private float lastY2 = -1;


    private void onTwoTouch(MotionEvent event) {
        float x1 = event.getX(0);
        float y1 = event.getY(0);
        float x2 = event.getX(1);
        float y2 = event.getY(1);
        if (event.getAction() == MotionEvent.ACTION_POINTER_DOWN) {
            isScale = true;
            distance = (float) Math.abs(Math.sqrt(Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2)));
        } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
            //缩放手势
            if (distance == 0) {
                distance = (float) Math.abs(Math.sqrt(Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2)));
            } else {
                float tempD = (float) Math.abs(Math.sqrt(Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2)));
                float d = tempD - distance;
                if (Math.abs(d) > 50) {
                    //第一次是否是错误的点,可能是上次的
                    distance = (float) Math.abs(Math.sqrt(Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2)));
                } else {
                    isScale = true;
                    if (d > 0) {
                        this.listener.onLarge(d, getCenter(x1, x2), getCenter(y1, y2));
                    } else if (d < 0) {
                        this.listener.onDecrease(Math.abs(d), getCenter(x1, x2), getCenter(y1, y2));
                    }
                    distance = (float) Math.abs(Math.sqrt(Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2)));
                }

            }
        } else if (event.getAction() == MotionEvent.ACTION_POINTER_UP) {
            distance = 0;
        }

        //旋转手势,触碰获得坐标点
        if (event.getAction() == MotionEvent.ACTION_POINTER_DOWN) {
            lastX1 = x1;
            lastY1 = y1;
            lastX2 = x2;
            lastY2 = y2;
        } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
            if (lastX1 == -1 ||
                    lastY1 == -1 ||
                    lastX2 == -1 ||
                    lastY2 == -1) {
                lastX1 = x1;
                lastY1 = y1;
                lastX2 = x2;
                lastY2 = y2;
            } else {
                //计算两条直线的方程
                //y=kx+b
                //第一条直线
                double k1;
                double b1;
                //先求出斜率
                k1 = (lastY1 - lastY2) / (lastX1 - lastX2);
                //求出b
                b1 = (lastY2 * lastX1 - lastY1 * lastX2) / (lastX1 - lastX2);

                //第二条直线
                //先求出斜率
                double k2 = (y1 - y2) / (x1 - x2);
                //求出b
                double b2 = (y2 * x1 - y1 * x2) / (x1 - x2);
                //斜率不相等才有交点
                if (k1 != k2) {
                    //计算交点坐标
                    double centerX = (b2 - b1) / (k1 - k2);
                    double centerY = (b2 * k1 - b1 * k2) / (k1 - k2);

                    //计算交点是否在两条直线上
                    double lastMaxX = lastX1 > lastX2 ? lastX1 : lastX2;
                    double lastMinX = lastX1 < lastX2 ? lastX1 : lastX2;
                    double lastMaxY = lastY1 > lastY2 ? lastY1 : lastY2;
                    double lastMinY = lastY1 < lastY2 ? lastY1 : lastY2;
                    double maxX = x1 > x2 ? x1 : x2;
                    double minX = x1 < x2 ? x1 : x2;
                    double maxY = y1 > y2 ? y1 : y2;
                    double minY = y1 < y2 ? y1 : y2;
                    if (centerX < lastMaxX &&
                            centerX > lastMinX &&
                            centerY < lastMaxY &&
                            centerY > lastMinY &&
                            centerX < maxX &&
                            centerX > minX &&
                            centerY < maxY &&
                            centerY > minY) {
                        //移动计算角度
                        //分别计算第一次的触碰的半径的平方,即两点距离公式的平方,两个手指一动分别形成两个三个型A,B
                        //A半径^2
                        double A_R1 = (Math.pow(lastX1 - centerX, 2) + Math.pow(lastY1 - centerY, 2));
                        //B半径^2
                        double B_R1 = (Math.pow(lastX2 - centerX, 2) + Math.pow(lastY2 - centerY, 2));
                        //然后计算一动后产生的第二次的半径
                        //A半径^2
                        double A_R2 = (Math.pow(x1 - centerX, 2) + Math.pow(y1 - centerY, 2));
                        //B半径^2
                        double B_R2 = (Math.pow(x2 - centerX, 2) + Math.pow(y2 - centerY, 2));
                        //然后计算两端的第三段长度,形成一个三角形
                        //A形成的第三条边
                        double A_A3 = (Math.pow(lastX1 - x1, 2) + Math.pow(lastY1 - y1, 2));
                        //B形成的第三条边
                        double B_A3 = (Math.pow(lastX2 - x2, 2) + Math.pow(lastY2 - y2, 2));
                        //然后用余弦定理分别把角求出
                        // <c=(a^2+b^2-c^2)/(2ab),a,b,c分别为三角形的三条边长
                        //A三角形的角度余弦值
                        double A_AngleCos = (A_R1 + A_R2 - A_A3) / (2 * Math.sqrt(A_R1) * Math.sqrt(A_R2));
                        //是否超出定义范围,余弦值定义为[-1,1]
                        A_AngleCos = A_AngleCos > 1 ? 1 : A_AngleCos;
                        A_AngleCos = A_AngleCos < -1 ? -1 : A_AngleCos;
                        //B三角形的角度余弦值
                        double B_AngleCos = (B_R1 + B_R2 - B_A3) / (2 * Math.sqrt(B_R1) * Math.sqrt(B_R2));
                        //是否超出定义范围,余弦值定义为[-1,1]
                        B_AngleCos = B_AngleCos > 1 ? 1 : B_AngleCos;
                        B_AngleCos = B_AngleCos < -1 ? -1 : B_AngleCos;
                        //判断向量方向
                        boolean isClockwiseA = ((lastX1 - centerX) * (y1 - centerY) - (lastY1 - centerY) * (x1 - centerX)) > 0;
                        boolean isClockwiseB = ((lastX2 - centerX) * (y2 - centerY) - (lastY2 - centerY) * (x2 - centerX)) > 0;
                        //A角大小,Math.acos弧度转换成角度
                        double A_Angle = Math.toDegrees(Math.acos(A_AngleCos));
                        //B角大小
                        double B_Angle = Math.toDegrees(Math.acos(B_AngleCos));
                        //计算得出的余弦值转换角度
                        double angle = A_Angle > B_Angle ? A_Angle : B_Angle;
                        boolean isClockwise = A_Angle > B_Angle ? isClockwiseA : isClockwiseB;
                        if (angle > 10 || angle < -10 || angle == Double.NaN || angle == Double.NEGATIVE_INFINITY || angle == Double.POSITIVE_INFINITY) {
                            Log.e("NAN", "lastX1=" + lastX1 + ",lastY1=" + lastY1 + ",x1=" + x1 + ",y1=" + y1 + ",centerX=" + centerX + ",centerY=" + centerY + ",angle=" + angle);
                            lastX1 = x1;
                            lastY1 = y1;
                            lastX2 = x2;
                            lastY2 = y2;
                        } else {
                            this.listener.onRotate((float) (isClockwise ? -angle : angle), (float) centerX, (float) centerY);
                        }
                    } else {
                        lastX1 = -1;
                        lastY1 = -1;
                        lastX2 = -1;
                        lastY2 = -1;
                    }


                }
                lastX1 = x1;
                lastY1 = y1;
                lastX2 = x2;
                lastY2 = y2;
            }
        } else if (event.getAction() == MotionEvent.ACTION_POINTER_UP) {
            lastX1 = -1;
            lastY1 = -1;
            lastX2 = -1;
            lastY2 = -1;
        }

    }

    //计算两点的中心点
    private float getCenter(float v1, float v2) {
        return (v1 + v2) / 2;
    }
}

这就是这几个手势的全部代码,使用更简单方便,上上上上代码:

import android.view.MotionEvent;
import android.view.View;

/**
 * Created by mr.Hao on 20**/**/**.
 */
public class MyView extends View implements OnGestuerListner {
    //获得手势实例
    private GestuerControl gestuerControl = new GestuerControl(this);


     @Override
    public boolean onTouchEvent(MotionEvent event) {
        boolean flag = gestuerControl.OnEvent(event);
        if (!flag) {
            return super.onTouchEvent(event);
        }
        return true;
    }


    @Override
    public boolean onOneTouch(MotionEvent event) {
        return true;
    }

    @Override
    public void onTranslate(float x, float y) {

    }

    @Override
    public void onLarge(float px, float centerX, float centerY) {
        
    }

    @Override
    public void onDecrease(float px, float centerX, float centerY) {
        
    }

    @Override
    public void onRotate(float degree, float centerX, float centerY) {
        
    }

    @Override
    public void onDoubleClick() {
       
    }

    

}

到这里的话,操作已经全部完成了,手势动作就是:

单个手指移动:触发onTranslate 移动

两个手指同时向一个方向旋转:触发onRotate 旋转

两个手指同一直线上反方向移动:触发 onDecrease 缩小 和 onLarge 放大

单个手指双击屏幕:触发 onDoubleClick 双击

okok!!结束了!!!很简单!!!需要的赶紧cv大法。

转载请注明!

猜你喜欢

转载自blog.csdn.net/thomas_red/article/details/84754934