我尝试了很多解决方案,但找不到任何有效的方法。列表视图中的每个元素都占据整个屏幕。我想通过使用垂直滑动手势从一个元素导航到下一个元素。我现在的设置现在有自由滚动,但我想禁用它,只允许垂直向上和向下滑动。每次滑动(取决于方向)都应该将我带到列表视图中的下一个连续元素并捕捉到位。
这是我目前的代码:
@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;
}
}
我该如何实现这一目标?
答案 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()