【问题标题】:Horizontal swipe not detected in ScrollView's parent [duplicate]在 ScrollView 的父级中未检测到水平滑动 [重复]
【发布时间】:2011-11-30 13:20:11
【问题描述】:

可能重复:
Gesture detection and ScrollView issue

编辑: 询问完整代码的问题here


我有一个孩子的布局。我设置了一个手势监听器来检测布局上的水平滑动。当布局是 LinearLayout 时,会正确检测到滑动,但当它是 ScrollView 时,则不会。我猜手势首先被 ScrollView 检测到,并没有传播到它的后代,但我不知道如何解决它。

这是我的布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent" android:layout_height="fill_parent"
    android:orientation="vertical">
    <ImageView android:layout_width="320dp" android:layout_height="30dp"
            android:src="@drawable/header"/>
    <ScrollView android:layout_width="fill_parent" android:layout_height="wrap_content">
        <!-- stuff -->
    </ScrollView>
</LinearLayout>

我为我的布局设置了以下监听器:

class ProductGestureListener extends SimpleOnGestureListener {

    @Override
    public boolean onDown(MotionEvent e) {
        return true;
    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {

        final int SWIPE_MIN_DISTANCE = 120;
        final int SWIPE_MAX_OFF_PATH = 250;
        final int SWIPE_THRESHOLD_VELOCITY = 200;            

        try {
            if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
                return false;
            if(e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {                   
                // show previous item
            }  else if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
               // show next item
            }
        } catch (Exception e) {
        }           
        return false;
    }
}

【问题讨论】:

  • 这个问题应该提供答案stackoverflow.com/questions/2646028/…
  • 我试过了,但仍然没有检测到布局上的滑动。
  • 几天前我使用了该链接的答案,它对我有用,你能发布你的布局文件和相关代码吗?
  • 我将手势监听器的代码添加到我的布局中。
  • 我并不是说将手势检测器附加到布局中,而是发布布局 xml 文件,但我认为我看到了问题,我会在答案中发布

标签: android scrollview gesture


【解决方案1】:

如果您希望整个Activity 可以水平滑动,您可以将以下内容用作Activity 的超类:

public abstract class SwipeActivity extends Activity {
   private static final int SWIPE_MIN_DISTANCE = 120;
   private static final int SWIPE_MAX_OFF_PATH = 250;
   private static final int SWIPE_THRESHOLD_VELOCITY = 200;
   private GestureDetector gestureDetector;

   @Override
   protected void onCreate( Bundle savedInstanceState ) {
      super.onCreate( savedInstanceState );
      gestureDetector = new GestureDetector( new SwipeDetector() );
   }

   private class SwipeDetector extends SimpleOnGestureListener {
      @Override
      public boolean onFling( MotionEvent e1, MotionEvent e2, float velocityX, float velocityY ) {

         // Check movement along the Y-axis. If it exceeds SWIPE_MAX_OFF_PATH,
         // then dismiss the swipe.
         if( Math.abs( e1.getY() - e2.getY() ) > SWIPE_MAX_OFF_PATH )
            return false;

         // Swipe from right to left.
         // The swipe needs to exceed a certain distance (SWIPE_MIN_DISTANCE)
         // and a certain velocity (SWIPE_THRESHOLD_VELOCITY).
         if( e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs( velocityX ) > SWIPE_THRESHOLD_VELOCITY ) {
            next();
            return true;
         }

         // Swipe from left to right.
         // The swipe needs to exceed a certain distance (SWIPE_MIN_DISTANCE)
         // and a certain velocity (SWIPE_THRESHOLD_VELOCITY).
         if( e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs( velocityX ) > SWIPE_THRESHOLD_VELOCITY ) {
            previous();
            return true;
         }

         return false;
      }
   }

   @Override
   public boolean dispatchTouchEvent( MotionEvent ev ) {
      // TouchEvent dispatcher.
      if( gestureDetector != null ) {
         if( gestureDetector.onTouchEvent( ev ) )
            // If the gestureDetector handles the event, a swipe has been
            // executed and no more needs to be done.
            return true;
      }
      return super.dispatchTouchEvent( ev );
   }

   @Override
   public boolean onTouchEvent( MotionEvent event ) {
      return gestureDetector.onTouchEvent( event );
   }

   protected abstract void previous();

   protected abstract void next();
}

您需要做的就是在扩展SwipeActivity 之后实现next()previous() 方法。

【讨论】:

    【解决方案2】:

    我必须添加

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev){
        super.dispatchTouchEvent(ev);    
        return productGestureDetector.onTouchEvent(ev); 
    }
    

    将此方法添加到使用 swiper 的 Activity 类中,就像 onCreate 方法一样。

    【讨论】:

      【解决方案3】:

      android的事件顺序是这样的

      用户执行一些操作 -> 动作被传递给父级 ->如果父处理动作,则动作被消耗 ->else 将动作传递给孩子 ->如果孩子处理动作,则动作被消耗 -> 否则该动作被传递

      这个过程一直持续到动作被消费或所有孩子都收到了动作并且没有人处理它。

      要检测滚动视图中的水平滑动并将其传递给子视图而不是滚动视图消耗它,需要拦截事件。

      即 用户执行一些操作 -> 动作被传递给父级 ->如果水平滑动传递给孩子 -> 否则让滚动视图处理动作

      为此(如这里的最佳答案中所述:HorizontalScrollView within ScrollView Touch Handling),在滚动视图中使用手势检测器,其唯一目的是检测手势是水平的还是垂直的。

      如果手势是水平的,那么我们想要拦截事件并将其传递给孩子。

      您需要创建一个自定义滚动视图,然后在那里实现一个手势检测器并从 onInterceptTouch() 调用它。通过在此处返回 true 或 false,我们可以说明是否在此处使用事件,您需要的一切都在上面的链接中。

      【讨论】:

      • 如果我用 LinearLayout 替换 ScrollView,这可行,但使用 ScrollView,父级上的手势监听器永远不会触发...
      • 您的手势检测器到底放在哪里?
      • 我用我的所有代码问了一个新问题:stackoverflow.com/questions/8330187/…
      猜你喜欢
      • 1970-01-01
      • 2019-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多