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

14

我遇到了一个非常类似的问题,在这里描述,只是我不是使用ScaleAnimation,而是在我的RelativeLayout中允许捏合缩放/平移。

缩放/平移功能完美地工作,但无论我的视图如何平移/缩放,可点击区域都不会随着视觉表示而改变。以下是我的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);
}

并且我的dispatchDraw:

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

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

如何根据画布的缩放/变换修改可点击区域?
2个回答

9

既然您已经重写了 dispatchTouchEvent,您可以尝试以下步骤:

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

TIP:您可以使用以下方法来评估 MotionEvent 是否在一定程度上容忍拦截 View

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;
}

1
通过这种解决方案,这是否意味着我需要检查布局中的每个可交互视图(按钮、编辑框等)?这似乎相当低效。 - TtT23
1
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - bonnyz

0

我猜你正在使用View Animations,但我更喜欢使用Property animations

这是来自Android文档的摘录(请参见高亮部分)

视图动画系统提供了仅对View对象进行动画处理的功能。因此,如果您想要对非View对象执行动画处理,则必须编写自己的代码来实现。视图动画系统还受到限制,因为它仅公开View对象的一些方面以进行动画处理,例如View的缩放和旋转,但不包括背景颜色等其他内容。
另一个缺点是视图动画系统仅修改了View绘制的位置,而没有真正地修改View本身。例如,如果您将按钮设置为在屏幕上移动,则按钮可以正确绘制,但可以单击按钮的实际位置不会更改,因此必须编写自己的逻辑来处理这个问题。
使用属性动画系统,这些限制被完全消除,您可以对任何对象(视图和非视图)的任何属性进行动画处理,并且实际修改对象本身。属性动画系统在执行动画方面也更加稳健。在高层次上,您将动画器分配给要进行动画处理的属性,例如颜色、位置或大小,并且可以定义动画的各个方面,例如多个动画器的插值和同步处理等。
然而,相比较而言,视图动画系统需要更少的时间进行设置,并且需要编写更少的代码。如果视图动画能够完成您需要完成的所有操作,或者如果您的现有代码已经按照您想要的方式工作,则无需使用属性动画系统。如果使用情况出现,使用两个动画系统处理不同的情况也是有意义的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接