【问题标题】:Android scaling/transforming canvas doesn't modify clickable areaAndroid缩放/转换画布不会修改可点击区域
【发布时间】:2015-07-14 03:56:22
【问题描述】:

我遇到了一个非常相似的问题 described here,除了不使用 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();
}

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

【问题讨论】:

    标签: java android canvas


    【解决方案1】:

    既然你已经在使用dispatchTouchEvent,你可以试试这个:

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

    提示:您可以使用下面的方法来评估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;
    }
    

    【讨论】:

    • 使用此解决方案,这是否意味着我需要检查布局上的每个可交互视图(按钮、edittext 等)?这似乎相当低效。
    • @l46kok 是的,我知道。如果您想手动处理触摸事件的调度,这是要付出的代价:)
    【解决方案2】:

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

    Android 文档摘录(见突出显示)

    视图动画系统提供了仅动画视图的能力 对象,所以如果你想动画非视图对象,你必须 实现你自己的代码来做到这一点。视图动画系统也是 受限于它只暴露视图的几个方面 要动画的对象,例如视图的缩放和旋转,但不是 例如背景颜色。

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

    有了属性动画系统,这些约束就完全没有了 删除,您可以为任何对象的任何属性(视图和 非视图)并且对象本身实际上已被修改。该物业 动画系统在执行方式上也更加健壮 动画。在高层次上,您将动画师分配给属性 您想要制作动画的内容,例如颜色、位置或大小,并且可以 定义动画的各个方面,例如插值和 多个动画师的同步。

    但是,视图动画系统的设置和设置时间更短 需要更少的代码来编写。如果视图动画完成了一切 您需要做的事情,或者如果您现有的代码已经可以正常工作 你想要的,没有必要使用属性动画系统。它 将两种动画系统用于不同的场景也可能有意义 用例出现时的情况。

    【讨论】:

      猜你喜欢
      • 2017-03-16
      • 2019-03-09
      • 1970-01-01
      • 2018-11-10
      • 2021-06-04
      • 1970-01-01
      • 2014-02-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多