Android - 处理列表视图项目上的点击和滑动

时间:2015-02-15 02:16:15

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

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

  

的OnClick
  如果用户点击该项,则应启动一项活动。每个按钮都会启动不同的活动。

     

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

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

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

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

以下是我到目前为止的片段:

    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设置为自定义适配器中的每个View。但它没有用......我无法弄清楚原因。

这就是我设置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;
}

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

2 个答案:

答案 0 :(得分:4)

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

根据我收集的内容,GestureDetector通过ListView附加到OnTouchListenerOnClickListener设置在各个列表项上 - 这是儿童ListView的观点。

由于触摸处理顺序,这是一个问题。 ListView(实际上任何ViewGroup)会先将触摸事件传递给其子视图,并直接处理事件 当且仅当 没有孩子时视图消耗事件。带有OnClickListener的子视图将始终使用触摸事件,因为它会针对点击事件跟踪它们...因此您现有的滑动检测器从不(或很少)看到任何事件。

最简单的解决方案可能是避免在两个元素之间分割触摸处理。对每个处理点击(即单击)和滑动的列表项使用一个GestureDetector - 并确保它们自己设置项目...而不是父项{{1} }}

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

答案 1 :(得分:0)

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

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