【问题标题】:Android - Handle click and swipe on listview itemsAndroid - 处理列表视图项目的点击和滑动
【发布时间】:2015-02-15 02:16:15
【问题描述】:

我正在制作一个菜单,其中的项目必须响应两种类型的事件:

OnClick
如果用户点击该项目,它应该启动一个 Activity。每个按钮启动一个不同的活动。

OnFling
当用户从右向左滑动项目时,应显示其名称。每个项目都有不同的名称,名称只会显示 在被刷过的项目中。

我尝试了很多不同的方法,在 StackOverflow 上搜索了很多教程和问题,但我找不到合适的答案,而且我的实现仍然很差。

我现在正在做的是为我的自定义适配器的方法getView 中的每个项目设置一个OnClick 句柄,并在我的listView 上设置一个gestureListener 并处理方法onFling,但它不是充当预期:大多数时候我尝试滑动并且手势被处理为点击......

我知道我可以使用像 this 这样的实现,但我认为 我不能在这种情况下使用 onTouch 事件技巧,因为我需要 视图位置所以我可以处理应该启动哪个活动(onTouch/click)或者哪个TextView应该变得可见。

这是我目前拥有的 sn-ps:

    final GestureDetector gestureDetector = new GestureDetector(
            new GestureListener());

    lvMenu.setOnTouchListener(new OnTouchListener() {
        @Override
        public boolean onTouch(final View view, final MotionEvent event) {
            if (gestureDetector.onTouchEvent(event)) {
                return false;
            }

            return true;
        }
    });

内部类:

class GestureListener extends SimpleOnGestureListener {
    protected MotionEvent mLastOnDownEvent = null;

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

    @Override
    public boolean onFling(final MotionEvent e1, final MotionEvent e2,
            final float velocityX, final float velocityY) {
        Log.d("OnFling", "Called");
        final int SWIPE_MIN_DISTANCE = 20;
        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 (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE
                    && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                Log.i("A", "Right to Left");
            } else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE
                    && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                Log.i("B", "Left to Right");
            }
        } catch (final Exception e) {
            // nothing
        }
        return super.onFling(e1, e2, velocityX, velocityY);
    }
}

还有我的自定义适配器中的onClick() 方法:

public void onClick(final View v) {
                Intent i = null;
                switch (position) {
                case 0:
                    i = new Intent(parent.getContext(),
                            ProfileActivity.class);
                    break;
                case 1:
                    i = new Intent(parent.getContext(),
                            CatalogActivity.class);
                    break;
                case 2:
                    i = new Intent(parent.getContext(), GuideActivity.class);
                    break;
                case 3:
                    i = new Intent(parent.getContext(),
                            EventsActivity.class);
                    break;
                default:
                    Log.d("MenuActivity", "Switch default case.");
                    break;
                }
                if (i != null) {
                    parent.getContext().startActivity(i);
                }

            }

谢谢你:)

编辑 1: 现在我正在尝试为自定义适配器中的每个视图设置一个 OnTouchListener。但它不起作用......我无法弄清楚原因。

这就是我设置 TouchListener 的方式:

            convertView.setOnTouchListener(new MenuGestureHandler() {

            @Override
            public boolean onSwipeRight() {
                Log.d("Swipe Right", "OK!");
                return true;
            }

            @Override
            public void onClick() {
                Log.d("Click", "OK!");
            }

        });

这是类(带有一些无用的代码,如 swipeUp、swipeDown):

public class MenuGestureHandler implements OnTouchListener {

GestureDetector gestureDetector = new GestureDetector(new GestureListener());

@Override
public boolean onTouch(final View v, final MotionEvent event) {
    return gestureDetector.onTouchEvent(event);
}

private final class GestureListener extends SimpleOnGestureListener {

    private static final int SWIPE_THRESHOLD = 100;
    private static final int SWIPE_VELOCITY_THRESHOLD = 100;

    @Override
    public boolean onSingleTapConfirmed(final MotionEvent e) {
        onClick(); // my method
        return super.onSingleTapConfirmed(e);
    }

    @Override
    public boolean onFling(final MotionEvent e1, final MotionEvent e2,
            final float velocityX, final float velocityY) {
        boolean result = false;
        try {
            final float diffY = e2.getY() - e1.getY();
            final float diffX = e2.getX() - e1.getX();
            if (Math.abs(diffX) > Math.abs(diffY)) {
                if (Math.abs(diffX) > SWIPE_THRESHOLD
                        && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                    if (diffX > 0) {
                        result = onSwipeRight();
                    } else {
                        result = onSwipeLeft();
                    }
                }
            } else {
                if (Math.abs(diffY) > SWIPE_THRESHOLD
                        && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
                    if (diffY > 0) {
                        result = onSwipeBottom();
                    } else {
                        result = onSwipeTop();
                    }
                }
            }
        } catch (final Exception exception) {
            exception.printStackTrace();
        }
        return result;
    }
}

public boolean onSwipeRight() {
    return false;
}

public boolean onSwipeLeft() {
    return false;
}

public void onClick() {
}

public boolean onSwipeTop() {
    return false;
}

public boolean onSwipeBottom() {
    return false;
}

EDIT 2 我可以通过在我的 GestureListener 类中重写 onDown() 方法并将其设置为始终返回 true 来使其工作。我真的不明白为什么我需要这样做,但现在看来它正在工作!

【问题讨论】:

    标签: android listview android-listview onclick android-gesture


    【解决方案1】:

    这里可能需要考虑一些问题,但最重要的是触摸事件的层次结构。

    据我所知,GestureDetector 通过OnTouchListener 附加到ListView,OnClickListener 设置在各个列表项上——它们是ListView 的子视图。

    这是因为触摸处理顺序的问题。 ListView(实际上是任何ViewGroup)将首先将触摸事件传递给其子视图,并直接处理事件当且仅当没有子视图消耗该事件.带有OnClickListener 的子视图将始终消耗触摸事件,因为它正在跟踪它们以查找点击事件……因此您现有的滑动检测器永远不会(或很少)看到任何事件。

    最简单的解决方案可能是避免在两个元素之间拆分触摸处理。为处理单击(即向上单击)和滑动的每个列表项使用单个 GestureDetector - 并确保在项目本身上设置它......而不是父 ListView。

    您也可以考虑观看我在Android Touch System 上的演讲,让您更详细地了解您正在处理的问题。

    【讨论】:

    • 好的,完美。现在我明白了这个问题......但我不能将 OnTouchListener 附加到每个项目,我不知道为什么!它只是不起作用......你能帮我吗?我用最新的代码编辑了我的帖子。非常感谢。
    【解决方案2】:

    我知道这是一个老问题,因为这里是未来搜索的答案:

    https://stackoverflow.com/a/44426980/6776960

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多