在 ScrollView 的父级中未检测到水平滑动

发布于 2024-12-18 19:00:18 字数 2059 浏览 3 评论 0原文

可能的重复:
手势检测和 ScrollView 问题

编辑:带有完整代码的问题在此处询问。


我有一个带孩子的布局。我设置了一个手势侦听器来检测布局上的水平滑动。当布局是 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;
    }
}

Possible Duplicate:
Gesture detection and ScrollView issue

EDIT: question with full code asked here.


I've got a layout with a child. I set a gesture listener to detect horizontal swipe on the layout. When the layout is a LinearLayout the swipe is properly detected, but when it's a ScrollView, it's not. I guess the gesture is first detected by the ScrollView and is not propagated to its ascendants, but I don't know how to solve it.

Here's my layout:

<?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>

I set the following listener to my layout:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

心的位置 2024-12-25 19:00:18

如果您希望整个 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();
}

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

If you want the whole Activity to be swipeable horizontally you can use the following as a super class for your 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();
}

All you need to do is implement the next() and previous() methods after extending SwipeActivity.

怪我入戏太深 2024-12-25 19:00:18

我必须

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

在您的活动类中添加添加此方法,该方法使用 swiper 就像 onCreate 方法一样。

I had to add

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

Add this method in your activity class which uses swiper just like the onCreate method.

预谋 2024-12-25 19:00:18

Android 的事件顺序是该

用户执行某些操作
->动作被传递给父级
->如果父进程处理操作,则该操作将被消耗
->否则该操作将传递给子级
->如果子进程处理动作,则该动作被消耗
->否则,该操作将继续传递到

该过程,直到该操作被消耗或所有子级都已收到该操作并且没有人处理该操作。

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

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

执行此操作的操作(如此处顶部答案中所述:ScrollView 触摸处理中的 Horizo​​ntalScrollView )在滚动视图中使用手势检测器,其唯一目的是检测手势是水平还是垂直。

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

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

The sequence of events for android is this

user performs some action
-> action is passed to parent
->if parent handles action then the action is consumed
->else the action is passed to a child
->if child handles action then the action is consumed
->else the action is passed on

this process continues until the action is consumed or all children have received the action and none of them handled it.

To detect a horizontal swipe in a scroll view and pass it to a child instead of the scroll view consuming it the event needs to be intercepted.

ie
user performs some action
-> action is passed to parent
->if horizontal swipe pass to child
-> else have the scroll view handle the action

to do this (as out lined in the top answer here: HorizontalScrollView within ScrollView Touch Handling ) a gesture detector is used in the scroll view for the sole purpose of detecting whether the gesture is horizontal or vertical.

If the gesture is horizontal then we want to intercept the event and pass it to the child.

You need to create a custom scrollview then implement a gesture detector there and call it from onInterceptTouch(). By returning true or false here we can say whether or not to consume the event here, everything you need is in that link above.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文