视图之间的尴尬触摸事件传播

Jas*_*son 6 android android-gallery

我有一个Gallery完整的ImageViews,ImageViews是可以缩放和可翻译的.我的目标是,一旦一个ImageView不能再转换为左/右,Gallery就会滚动.因此有时ImageView需要处理触摸事件,有时Gallery需要处理触摸事件.我在我ImageViewonTouchEvent方法中有逻辑,因为当我希望发生切换时,我会得到意想不到的结果.我会在显示代码后解释问题:

// PinchZoomImageView.java

@Override
public boolean onTouchEvent( MotionEvent event ) {

    Log.i( "PinchZoomImageView", "IM GETTING TOUCHED!" );

    if ( isPassThroughTouchEvent() ) {
        Log.i( "PinchZoomImageView", "IM RETURNING FALSE!" );
        return false;
    }

    getScaleDetector().onTouchEvent( event );

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

            setLastTouchX( x );
            setLastTouchY( y );
            setActivePointerId( event.getPointerId( 0 ) );

            break;
        }

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

            // Only move if the ScaleGestureDetector isn't processing a gesture.
            if ( !getScaleDetector().isInProgress() ) {
                if ( isDetectMovementX() ) {
                    final float dx = x - getLastTouchX();
                    setPosX( getPosX() + dx );
                }

                if ( isDetectMovementY() ) {
                    final float dy = y - getLastTouchY();
                    setPosY( getPosY() + dy );
                }

                invalidate();
            }

            setLastTouchX( x );
            setLastTouchY( y );

            if ( isAtXBound() && !isPassThroughTouchEvent() ) {

                setPassThroughTouchEvent( true );
            }

            break;
        }

        case MotionEvent.ACTION_UP: {
            setActivePointerId( INVALID_POINTER_ID );
            break;
        }

        case MotionEvent.ACTION_CANCEL: {
            setActivePointerId( INVALID_POINTER_ID );
            break;
        }

        case MotionEvent.ACTION_POINTER_UP: {
            final int pointerIndex = ( event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK ) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
            final int pointerId = event.getPointerId( pointerIndex );
            if ( pointerId == getActivePointerId() ) {
                // This was our active pointer going up. Choose a new
                // active pointer and adjust accordingly.
                final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
                setLastTouchX( event.getX( newPointerIndex ) );
                setLastTouchY( event.getY( newPointerIndex ) );
                setActivePointerId( event.getPointerId( newPointerIndex ) );
            }
            break;
        }
    }

    return true;
}
Run Code Online (Sandbox Code Playgroud)

这是我的Gallery.我覆盖了onTouchEvent只是为了表明接收触摸事件的时间.

// SwipeGallery.java

@Override
public boolean onTouchEvent( MotionEvent event ) {

    Log.i( "SwipeGallery", "IM GETTING TOUCHED!" );
    return super.onTouchEvent( event );
}
Run Code Online (Sandbox Code Playgroud)

所以当我加载活动时,我会尝试从右向左滑动.传递动作事件的逻辑立即被触发,但这是我的日志输出.

08-02 10:04:47.097: INFO/PinchZoomImageView(17189): IM GETTING TOUCHED!
08-02 10:04:47.179: INFO/PinchZoomImageView(17189): IM GETTING TOUCHED!
08-02 10:04:47.179: INFO/PinchZoomImageView(17189): IM GETTING TOUCHED!
08-02 10:04:47.179: INFO/PinchZoomImageView(17189): IM RETURNING FALSE!
08-02 10:04:47.230: INFO/PinchZoomImageView(17189): IM GETTING TOUCHED!
08-02 10:04:47.230: INFO/PinchZoomImageView(17189): IM RETURNING FALSE!
08-02 10:04:47.230: INFO/PinchZoomImageView(17189): IM GETTING TOUCHED!
08-02 10:04:47.230: INFO/PinchZoomImageView(17189): IM RETURNING FALSE!
08-02 10:04:47.245: INFO/PinchZoomImageView(17189): IM GETTING TOUCHED!
08-02 10:04:47.245: INFO/PinchZoomImageView(17189): IM RETURNING FALSE!
08-02 10:04:47.261: INFO/PinchZoomImageView(17189): IM GETTING TOUCHED!
08-02 10:04:47.261: INFO/PinchZoomImageView(17189): IM RETURNING FALSE!
08-02 10:04:47.277: INFO/PinchZoomImageView(17189): IM GETTING TOUCHED!
08-02 10:04:47.277: INFO/PinchZoomImageView(17189): IM RETURNING FALSE!
08-02 10:04:47.296: INFO/PinchZoomImageView(17189): IM GETTING TOUCHED!
08-02 10:04:47.296: INFO/PinchZoomImageView(17189): IM RETURNING FALSE!
08-02 10:04:47.312: INFO/PinchZoomImageView(17189): IM GETTING TOUCHED!
08-02 10:04:47.312: INFO/PinchZoomImageView(17189): IM RETURNING FALSE!
08-02 10:04:47.327: INFO/PinchZoomImageView(17189): IM GETTING TOUCHED!
08-02 10:04:47.327: INFO/PinchZoomImageView(17189): IM RETURNING FALSE!
08-02 10:04:47.343: INFO/PinchZoomImageView(17189): IM GETTING TOUCHED!
08-02 10:04:47.343: INFO/PinchZoomImageView(17189): IM RETURNING FALSE!
08-02 10:04:47.360: INFO/PinchZoomImageView(17189): IM GETTING TOUCHED!
08-02 10:04:47.360: INFO/PinchZoomImageView(17189): IM RETURNING FALSE!
....etc.
Run Code Online (Sandbox Code Playgroud)

第二次我从右向左滑动,我明白了:

08-02 10:27:31.573: INFO/PinchZoomImageView(17189): IM GETTING TOUCHED!
08-02 10:27:31.573: INFO/PinchZoomImageView(17189): IM RETURNING FALSE!
08-02 10:27:31.573: INFO/SwipeGallery(17189): IM GETTING TOUCHED!
08-02 10:27:31.636: INFO/SwipeGallery(17189): IM GETTING TOUCHED!
08-02 10:27:31.636: INFO/SwipeGallery(17189): IM GETTING TOUCHED!
08-02 10:27:31.683: INFO/SwipeGallery(17189): IM GETTING TOUCHED!
08-02 10:27:31.933: INFO/SwipeGallery(17189): IM GETTING TOUCHED!
08-02 10:27:31.964: INFO/SwipeGallery(17189): IM GETTING TOUCHED!
08-02 10:27:31.999: INFO/SwipeGallery(17189): IM GETTING TOUCHED!
08-02 10:27:32.034: INFO/SwipeGallery(17189): IM GETTING TOUCHED!
Run Code Online (Sandbox Code Playgroud)

这种"imageview始终处理的第一个动作事件,画廊总是处理的第二个动作事件"的模式将永远持续下去(为画廊中的每个位置创建一个新的imageview,这就是为什么isPassThroughTouchEvent()返回false的第3个,第5个等时间).那么我到底错过了什么?我认为返回false会传播触摸事件直到它被处理,但是Gallery第一次不会采取它,但第二次呢?这对我来说毫无意义.有人有主意吗?谢谢.

Ric*_*Lee 3

当视图在向下 ( ACTION_DOWN) 运动事件上​​返回 true 时,该视图将被“锁定”为触摸运动目标。这意味着它将接收后续运动事件,直到最终的向上事件,无论它发生在屏幕上的哪个位置(请参阅此线程),除非其父级希望允许拦截该事件。

解释一下你的情况:

  1. 在第一次滑动时,您ImageView处理了向下运动,这使其成为运动目标(请参阅日志)。这意味着所有后续的运动事件都将传递给它,并且由于您Gallery没有拦截这些事件,因此onTouchEvent不会调用它的处理程序。

  2. 在第二次滑动时,您ImageView不处理向下动作(在日志中显示为“IM GETTING TOUCH!”+“IM RETURNING FALSE!”)并将事件传递给下一个处理程序,在这种情况下,它将Gallery运行其onTouchEvent处理程序。默认情况下,Gallery始终处理向下事件,这会将其锁定为运动目标。