Android手指触摸实现文字放大缩小(多点触控)

目录

效果展示

多点触控讲解

●什么是多点触控
多点触控说白了就是一个以上的手指同时触摸屏幕,比如说你看一张图片的时候想要放大来看,这时你需要用两个手指从屏幕中心向四周扩张滑动,这个也是多点触控的应用。
●多点触控的触摸事件
多点触控的触摸事件的处理与正常的触摸事件一样都是在onTouchEvent方法中处理的,但是这里也有三个不同点:
1.多点触控需要用event.getActionMasked()来获取Action
2.第二根手指及第二根以上的手指触摸屏幕的时候匹配的是MotionEvent.ACTION_POINTER_DOWN,第一根手指触摸时还是匹配MotionEvent.ACTION_DOWN这个没变
3.除最后一根手指的其他手指离开屏幕的时候匹配的是MotionEvent.ACTION_POINTER_UP,最后一根手离开屏幕时还是匹配MotionEvent.ACTION_UP这个没变
具体代码如下:

@Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getActionMasked()){
            case MotionEvent.ACTION_DOWN:
                //第一根手指触摸触发
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                //第二根手指及以上触摸触发
                break;
            case MotionEvent.ACTION_MOVE:

                break;
            case MotionEvent.ACTION_POINTER_UP:
                //除最后一根手指其他手指离开时触发
                break;
            case MotionEvent.ACTION_UP:
                //最后一根手指离开时触发
                break;
        }
        return true;
    }

●触摸点的标识
某个触摸点可以通过两种方式来确定:
1.通过id(PointerId)
2.通过索引(PointerIndex)
这里有着对应的几个方法:

//根据PointerId获取索引,传参为PointerId
event.findPointerIndex();
//根据索引获取PointerId,传参为PointerIndex
event.getPointerId();
//获取当前触摸点的索引
event.getActionIndex();
//获取当前所有触摸点的数量
event.getPointerCount();

这里触摸点的id和索引的值有如下的规律:
触摸点的PointerId和索引PointerIndex都是从0开始取值的,但是PointerId的值是一直不变的而PointerIndex的值会随着屏幕上的触摸点的减少或增加而改变,具体入下图所示:

事件 PointerId PointerIndex
依次按下三根手指 三根手指的PointerId依次为0、1、2 三根手指的PointerIndex依次为0、1、2
抬起第二根手指 第一根手指的PointerId为0,第三根手指的PointerId为2 第一根手指的PointerIndex为0,第三根手指的PointerIndex变为1
抬起第一根手指 第三根手指的PointerId为2 第三根手指的PointerIndex变为0

另外我们也可以通过遍历event.getPointerCount()来获取所有的触摸点的信息,如下所示:

for (int i = 0; i < event.getPointerCount(); i++) {
      //根据上面表格展示的规律我们可以知道触摸点的PointerIndex与i是一致的
      //这里我们根据getX和getY的重载方法来获取x和y的值,其中的参数传的是PointerIndex
      float x = event.getX(i);
      float y = event.getY(i);
}

到这里我们也算是基本了解了多点触控了,接下来我们就通过案例的讲解来加深印象

案例讲解

●逻辑确定
在动手写代码之前我们先来确定一下整个效果的实现逻辑,我们要实现的逻辑是触摸屏幕的两手指向四周扩散是放大,向中间聚拢是缩小,入下图所示:

两手指向中心聚拢

两手指向四周扩散

这里我们需要用来计算的值就是第一次触摸屏幕时两点之间的距离(AB)和滑动后两点之间的距离(A'B'):

而AB的长度的计算我们可以根据勾股定理算出来:

其中:
AC = 绝对值(A.getY - B.getY)
BC = 绝对值(B.getX - A.getX)

计算出滑动前两点的距离(AB)与滑动后两点的距离(A'B')后我们可以用A'B'与AB的比值来获取缩放的值即:
缩放值 = A'B' / AB
获取到缩放值之后我们就可以以当前文字的大小为基准根据缩放值来进行缩放了

●代码实现
确定了逻辑之后接下来我们就用代码来实现
根据效果图我们可以知道,我们要实现的效果是可以将文字放大缩小的,就类似于图片的放大缩小,这里为了方便我就直接继承了TextView来实现的,另外我们还需要记录初始的文字大小作为放大缩小的基准

public class ScaleTextView extends TextView {
    private float mTextSize;
    public ScaleTextView(Context context) {
        this(context,null);
    }
    public ScaleTextView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }
    public ScaleTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mTextSize = getTextSize();
    }
}

接下来我们先在onTouchEvent中计算出初始两触摸点之间的距离即:AB

private float mFirstTouchX;
private float mFirstTouchY;
private float mSecondTouchX;
private float mSecondTouchY;
private double firstPointerLength;
@Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getActionMasked()){
            case MotionEvent.ACTION_DOWN:
                //获取第一个点(A点)的位置
                mFirstTouchX = event.getX();
                mFirstTouchY = event.getY();
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                if(event.getActionIndex() == 1){
                    //获取第二个点(B点)的位置
                    mSecondTouchX = event.getX(1);
                    mSecondTouchY = event.getY(1);
                    
                    //根据两点的位置获取两个触摸点之间的距离(AB)
                    float firstLengthX = Math.abs(mFirstTouchX - mSecondTouchX);
                    float firstLengthY = Math.abs(mFirstTouchY - mSecondTouchY);
                    firstPointerLength = Math.sqrt(Math.pow(firstLengthX, 2) + Math.pow(firstLengthY, 2));
                }
                break;
        }
        return true;
    }

然后我们需要在滑动的时候获取滑动后的距离(A'B')

@Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getActionMasked()){
            case MotionEvent.ACTION_DOWN:
                //获取第一个点(A点)的位置
                mFirstTouchX = event.getX();
                mFirstTouchY = event.getY();
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                if(event.getActionIndex() == 1){
                    //获取第二个点(B点)的位置
                    mSecondTouchX = event.getX(1);
                    mSecondTouchY = event.getY(1);
                    //根据两点的位置获取两个触摸点之间的距离(AB)
                    float firstLengthX = Math.abs(mFirstTouchX - mSecondTouchX);
                    float firstLengthY = Math.abs(mFirstTouchY - mSecondTouchY);
                    firstPointerLength = Math.sqrt(Math.pow(firstLengthX, 2) + Math.pow(firstLengthY, 2));
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if(event.getPointerCount() >= 2){
                    //获取第一个点(A‘)的位置
                    float firstX = event.getX(0);
                    float firstY = event.getY(0);

                    //获取第二个点(B‘)的位置
                    float secondX = event.getX(1);
                    float secondY = event.getY(1);
                    
                    //计算两点之间的距离(A'B')
                    float secondLengthX = Math.abs(firstX - secondX);
                    float secondLengthY = Math.abs(firstY - secondY);
                    double secondPointerLength = Math.sqrt(Math.pow(secondLengthX, 2) + Math.pow(secondLengthY, 2));
                }
                break;
        }
        return true;
    }

然后我们可以根据计算出来的AB与A'B'的距离来计算缩放值了,代码如下:

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getActionMasked()){
            case MotionEvent.ACTION_DOWN:
                //获取第一个点(A点)的位置
                mFirstTouchX = event.getX();
                mFirstTouchY = event.getY();
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                if(event.getActionIndex() == 1){
                    //获取第二个点(B点)的位置
                    mSecondTouchX = event.getX(1);
                    mSecondTouchY = event.getY(1);
                    //根据两点的位置获取两个触摸点之间的距离(AB)
                    float firstLengthX = Math.abs(mFirstTouchX - mSecondTouchX);
                    float firstLengthY = Math.abs(mFirstTouchY - mSecondTouchY);
                    firstPointerLength = Math.sqrt(Math.pow(firstLengthX, 2) + Math.pow(firstLengthY, 2));
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if(event.getPointerCount() >= 2){
                    //获取第一个点(A‘)的位置
                    float firstX = event.getX(0);
                    float firstY = event.getY(0);

                    //获取第二个点(B‘)的位置
                    float secondX = event.getX(1);
                    float secondY = event.getY(1);

                    //计算两点之间的距离(A'B')
                    float secondLengthX = Math.abs(firstX - secondX);
                    float secondLengthY = Math.abs(firstY - secondY);
                    double secondPointerLength = Math.sqrt(Math.pow(secondLengthX, 2) + Math.pow(secondLengthY, 2));
                    //缩放文字
                    zoom(secondPointerLength);
                }
                break;
        }
        return true;
    }

    private void zoom(double secondPointerLength) {
        double scaleRate = secondPointerLength / firstPointerLength;
        float textSize = (float) (mTextSize * scaleRate);
        //这里也进行像素值赋值
        setTextSize(TypedValue.COMPLEX_UNIT_PX,textSize);
    }

最后也不要忘了在MotionEvent.ACTION_UP中保存当前文字的大小,否则下次缩放的时候文字会先一下子变小

@Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getActionMasked()){
            case MotionEvent.ACTION_UP:
                //手指抬起的时候记录当前的文字大小
                mTextSize = getTextSize();
                break;
        }
        return true;
    }

案例源码

https://gitee.com/itfitness/scale-text-view

你可能感兴趣的:(Android手指触摸实现文字放大缩小(多点触控))