Android 缩放/变换画布不会修改可点击区域

2022-09-04 03:58:41

我在这里描述了一个非常相似的问题,除了我允许在我的相对布局中捏合缩放/平移而不是使用ScaleAnimation。

缩放/平移工作完美,但无论如何平移/缩放我的视图,可单击区域都不会随可视表示而变化。以下是我的 dispatchTouchEvent 的样子:

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    if (mScaleGestureDetector != null && mGestureDetector != null) {
        mScaleGestureDetector.onTouchEvent(ev);
        mGestureDetector.onTouchEvent(ev);
    }

    final int action = ev.getAction();
    switch (action & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN: {
            final float x = ev.getX();
            final float y = ev.getY();

            mLastTouchX = x;
            mLastTouchY = y;
            mActivePointerId = ev.getPointerId(0);
            break;
        }

        case MotionEvent.ACTION_MOVE: {
            final int pointerIndex = ev.findPointerIndex(mActivePointerId);
            final float x = ev.getX(pointerIndex);
            final float y = ev.getY(pointerIndex);

            // Only move if the ScaleGestureDetector isn't processing a gesture.
            if (!mScaleGestureDetector.isInProgress() && mScaleFactor > 1f) {
                final float dx = x - mLastTouchX;
                final float dy = y - mLastTouchY;

                float newPosX = mPosX + dx;
                float newPosY = mPosY + dy;
                if (isCoordinateInBound(newPosX, mScreenSize.x))
                    mPosX = newPosX;
                if (isCoordinateInBound(newPosY, mScreenSize.y))
                    mPosY = newPosY;

                invalidate();
            }

            mLastTouchX = x;
            mLastTouchY = y;

            break;
        }

        case MotionEvent.ACTION_UP: {
            mActivePointerId = INVALID_POINTER_ID;
            break;
        }

        case MotionEvent.ACTION_CANCEL: {
            mActivePointerId = INVALID_POINTER_ID;
            break;
        }

        case MotionEvent.ACTION_POINTER_UP: {
            final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
                    >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
            final int pointerId = ev.getPointerId(pointerIndex);
            if (pointerId == mActivePointerId) {
                final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
                mLastTouchX = ev.getX(newPointerIndex);
                mLastTouchY = ev.getY(newPointerIndex);
                mActivePointerId = ev.getPointerId(newPointerIndex);
            }
            break;
        }
    }

    return super.dispatchTouchEvent(ev);
}

和我的调度草稿:

protected void dispatchDraw(Canvas canvas) {
    canvas.save(Canvas.MATRIX_SAVE_FLAG);
    canvas.translate(mPosX, mPosY);

    canvas.scale(mScaleFactor, mScaleFactor);
    super.dispatchDraw(canvas);
    canvas.restore();
}

如何根据画布的修改比例/变换来修改可点击区域?


答案 1

由于您已经在越野,因此您可以尝试此操作:dispatchTouchEvent

  1. 通过考虑当前的缩放/平移转换来手动评估每个;您可以通过对原始 m 应用反向缩放/平移变换创建新的(我们称之为 FakeMotionEvent)。MotionEventMotionEventMotionEvent
  2. 检查 FakeMotionEvent 是否拦截了特定的 v;这意味着用户触摸的位置表示v的用户可见性位置。View
  3. 如果 FakeMotionEvent 截获 v,则消耗电流并调用MotionEventv.dispatchTouchEvent(m);

提示:您可以使用以下方法来评估是否截获具有一定容差的 a:MotionEventView

private boolean intercept(MotionEvent ev, View view, float boundingBoxTolerance){
    if (boundingBoxTolerance < 1.0f) {
        boundingBoxTolerance = 1.0f;
    }
    try {
        if (ev != null && view != null) {
            int coords[] = new int[2];
            view.getLocationOnScreen(coords);
            if (ev.getRawX() >= ((float)coords[0]) / boundingBoxTolerance && ev.getRawX() <= coords[0] + ((float) view.getWidth()) * boundingBoxTolerance) {
                if(ev.getRawY() >= ((float)coords[1]) / boundingBoxTolerance && ev.getRawY() <= coords[1] + ((float) view.getHeight()) * boundingBoxTolerance)
                    return true;
            }
        }
    }
    catch (Exception e) {}
    return false;
}

答案 2

我猜你正在使用视图动画,我更喜欢使用属性动画

摘自安卓文档(见突出显示)

视图动画系统提供了仅对 View 对象进行动画处理的功能,因此,如果要对非 View 对象进行动画处理,则必须实现自己的代码才能执行此操作。视图动画系统还受到以下事实的限制:它仅公开 View 对象的几个方面以进行动画处理,例如视图的缩放和旋转,而不是背景色。

视图动画系统的另一个缺点是,它只修改了绘制视图的位置,而不是实际的视图本身。例如,如果您动画按钮在屏幕上移动,则该按钮可以正确绘制,但您可以单击按钮的实际位置不会更改,因此您必须实现自己的逻辑来处理此问题。

使用属性动画系统,这些约束将被完全删除,您可以对任何对象(视图和非视图)的任何属性进行动画处理,并且对象本身实际上被修改。属性动画系统在执行动画的方式上也更加健壮。在较高级别,您可以将动画师分配给要设置动画的属性(如颜色、位置或大小),并且可以定义动画的各个方面,如插值和多个动画师的同步。

但是,视图动画系统的设置时间更短,编写代码所需的时间也更少。如果视图动画完成了您需要执行的所有操作,或者您的现有代码已经按照您想要的方式工作,则无需使用属性动画系统。如果出现用例,将这两个动画系统用于不同的情况也可能是有意义的。


推荐