Android:列表视图上的垂直滑动(禁用滚动)

时间:2014-01-13 20:49:07

标签: java android android-listview gesture

我尝试了很多解决方案,但找不到任何有效的方法。列表视图中的每个元素都占据整个屏幕。我想通过使用垂直滑动手势从一个元素导航到下一个元素。我现在的设置现在有自由滚动,但我想禁用它,只允许垂直向上和向下滑动。每次滑动(取决于方向)都应该将我带到列表视图中的下一个连续元素并捕捉到位。

这是我目前的代码:

@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
    // TODO Auto-generated method stub
    switch (scrollState) {
    case OnScrollListener.SCROLL_STATE_IDLE:

            if (scrolling){
                // get first visible item
                  RelativeLayout item = (RelativeLayout) view.getChildAt(0);
                  int top = Math.abs(item.getTop()); // top is a negative value
                  int botton = Math.abs(item.getBottom());
                  if (top >= botton){

                     //((ListView)view).setSelectionFromTop(view.getFirstVisiblePosition()+1, 0);
                     ((ListView)view).smoothScrollToPositionFromTop(view.getFirstVisiblePosition()+1, 0, 1);

                  } else {
                         ((ListView)view).smoothScrollToPositionFromTop(view.getFirstVisiblePosition(), 0, 1);

                         }
                }

            scrolling = false;
   break;
    case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:


    case OnScrollListener.SCROLL_STATE_FLING:   
          scrolling = true;
          break;

    }
}

我该如何实现这一目标?

2 个答案:

答案 0 :(得分:4)

如果要禁用内置滚动功能,则需要稍微欺骗AbsListView并隐藏ACTION_MOVE运动事件。通过这种方式,您可以获得随ListView一起提供的所有触摸系统,但滚动将被禁用。

我在示例中所做的是将CANCEL事件发送到基础AbsListView并手动处理滚动触摸事件。

这是我想出的。可能不是最佳解决方案,但它证明了这个概念:)

/**
 * Created by paveld on 1/13/14.
 */
public class CustomListView extends ListView {

    private float touchSlop = 0;
    private float downY = 0;
    private boolean consumeTouchEvents = false;

    public CustomListView(Context context) {
        super(context);
        init();
    }

    public CustomListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public CustomListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
        touchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        boolean isHandled = true;
        switch (ev.getActionMasked()) {
            case MotionEvent.ACTION_MOVE:
                float distance = downY - ev.getY();
                if (!consumeTouchEvents && Math.abs(distance) > touchSlop) {

                    //send CANCEL event to the AbsListView so it doesn't scroll
                    ev.setAction(MotionEvent.ACTION_CANCEL);
                    isHandled = super.onTouchEvent(ev);
                    consumeTouchEvents = true;
                    handleScroll(distance);
                }
                break;
            case MotionEvent.ACTION_DOWN:
                consumeTouchEvents = false;
                downY = ev.getY();
                //fallthrough
            default:
                if (!consumeTouchEvents) {
                    isHandled = super.onTouchEvent(ev);
                }
                break;

        }
        return isHandled;
    }

    private void handleScroll(float distance) {
        if (distance > 0) {
            //scroll up
            if (getFirstVisiblePosition() < getAdapter().getCount() - 1) {
                smoothScrollToPositionFromTop(getFirstVisiblePosition() + 1, 0, 300);
            }
        } else {
            //scroll down
            if (getFirstVisiblePosition() > 0) {
                smoothScrollToPositionFromTop(getFirstVisiblePosition() - 1, 0, 300);
            }
        }
    }
}

答案 1 :(得分:1)

您始终可以覆盖listView的onTouchEvent()方法(可能需要子类化listView),以便您只执行滑动检测。

实施例。

@Override
public boolean onTouchEvent(MotionEvent motionEvent) {
    //TODO: perform the swipe detection functionality here

    //always return true so that the scrolling isn't performed by the list view
    return true; 
}

我没有对此进行测试,因此listView检测滚动的方式可能存在不规则之处。如果onTouchEvent()不起作用,您还应该查看onInterceptTouchEvent()