在scrollview内嵌套了一个viewpager,重写了scrollview的onInterceptTouchEvent()方法,但是我写的没有什么效果,最近刚刚接触这个滑动冲突不能很好理解。
public class ScrollViewX extends ScrollView {
private static final String TAG = "ScrollViewX";
private ViewPager mViewPager;
private int mLastXIntercepted = 0;
private int mLastYIntercepted = 0;
public ScrollViewX(Context context) {
super(context);
}
public ScrollViewX(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ScrollViewX(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean intercepted = false;
int x = (int) ev.getX();
int y = (int) ev.getY();
int deltaX = x - mLastXIntercepted;
int deltaY = y - mLastYIntercepted;
mLastXIntercepted = x;
mLastYIntercepted = y;
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
//action_down不拦截
intercepted = false;
break;
}
case MotionEvent.ACTION_MOVE: {
if(mViewPager != null && isTouchInView(mViewPager, ev)){
//点击事件发生在viewpager范围内
if(Math.abs(deltaY) > Math.abs(deltaX)) {
//如果竖直方向的滑动距离大于横向, 那么scrollview拦截
intercepted = true;
} else {
intercepted = false;
}
} else {
intercepted = false;
}
break;
}
case MotionEvent.ACTION_UP: {
intercepted = false;
break;
}
default: break;
}
return intercepted;
}
//判断点击事件是否在当前view中
private boolean isTouchInView(View view, MotionEvent event) {
int x = (int) event.getRawX();
int y = (int) event.getRawY();
int[] local = new int[2];
view.getLocationOnScreen(local);
int subVX = local[0];
int subVY = local[1];
int subWidth = view.getWidth();
int subHeight = view.getHeight();
if(x > subVX && x < subVX + subWidth && y > subVY && y < subVY + subHeight) {
return true;
}
return false;
}
public void setViewPager(ViewPager viewPager) {
mViewPager = viewPager;
}
}
我在红色部分左右滑动viewpager能够正常,但是在viewpager中竖直滑动就不能滚动scrollview,但是我觉得我在scrollview的onInterceptTouchEvent()方法中已经判断了,但是最终却没有效果。
感谢采纳的那位,根据他的提示, 我顺便解决了listview的滑动冲突。
现在使用外部拦截法: 重写ScrollView 的 onInterceptedTouchEvent() 方法,
public class ScrollViewX extends ScrollView {
private static final String TAG = "ScrollViewX";
private ListViewX mListViewX;
private ViewPager mViewPager;
private int mLastX = 0;
private int mLastY = 0;
public ScrollViewX(Context context) {
super(context);
}
public ScrollViewX(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ScrollViewX(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean intercepted = false;
int x = (int) ev.getX();
int y = (int) ev.getY();
int deltaX = x - mLastX;
int deltaY = y - mLastY;
Log.i(TAG, "deltaY = " + deltaY);
mLastX = x;
mLastY = y;
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
return super.onInterceptTouchEvent(ev);
}
case MotionEvent.ACTION_MOVE: {
if(mViewPager != null && isTouchInView(mViewPager, ev)){
//点击事件发生在viewpager范围内
if(Math.abs(deltaY) > Math.abs(deltaX)) {
//如果竖直方向的滑动距离大于横向, 那么scrollview拦截
return true;
} else {
return super.onInterceptTouchEvent(ev);
}
} else if(mListViewX != null && isTouchInView(mListViewX, ev)) {
if(atTopOrEnd(deltaY)) {
return true;
} else {
return false;
}
} else {
return super.onInterceptTouchEvent(ev);
}
}
case MotionEvent.ACTION_UP: {
return super.onInterceptTouchEvent(ev);
}
default:
break;
}
return super.onInterceptTouchEvent(ev);
}
//如果listView滑到顶端时当前事件向上滑动,需要scrollview接管, 在底端时类似。
private boolean atTopOrEnd(int len) {
int count = mListViewX.getCount();
int topId = mListViewX.getFirstVisiblePosition();
int endId = mListViewX.getLastVisiblePosition();
if((endId == count - 1 && len < 0)) {
View lastView = mListViewX.getChildAt(mListViewX.getChildCount() - 1);
if(lastView.getBottom() == mListViewX.getHeight()) {
return true;
}
}
if(topId == 0 && len > 0) {
View firstView = mListViewX.getChildAt(topId);
if(firstView.getTop() == 0) {
return true;
}
}
return false;
}
//判断点击事件是否在当前view中
private boolean isTouchInView(View view, MotionEvent event) {
int x = (int) event.getRawX();
int y = (int) event.getRawY();
int[] local = new int[2];
view.getLocationOnScreen(local);
int subVX = local[0];
int subVY = local[1];
int subWidth = view.getWidth();
int subHeight = view.getHeight();
if(x > subVX && x < subVX + subWidth && y > subVY && y < subVY + subHeight) {
return true;
}
return false;
}
public void setListViewX(ListViewX listViewX) {
mListViewX = listViewX;
}
public void setViewPager(ViewPager viewPager) {
mViewPager = viewPager;
}
}
采用内部拦截法: 重写listview 的 dispatchTouchEvent() 方法
public class ListViewX extends ListView {
private static final String TAG = "ListViewX";
private int mLastX = 0;
private int mLastY = 0;
public ListViewX(Context context) {
super(context);
}
public ListViewX(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ListViewX(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
//ListView 在 ScrollView中显示需要处理
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width;
int height;
if(widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) {
width = MeasureSpec.makeMeasureSpec(500, MeasureSpec.AT_MOST);
height = MeasureSpec.makeMeasureSpec(500, MeasureSpec.AT_MOST);
} else if(widthMode == MeasureSpec.AT_MOST) {
width = MeasureSpec.makeMeasureSpec(500, MeasureSpec.AT_MOST);
height = heightMeasureSpec;
} else if(heightMode == MeasureSpec.AT_MOST) {
width = widthMeasureSpec;
height = MeasureSpec.makeMeasureSpec(500, MeasureSpec.AT_MOST);
} else {
width = widthMeasureSpec;
height = heightMeasureSpec;
}
super.onMeasure(width, height);
}
//requestDisallowInterceptTouchEvent参数为false表示父容器拦截
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int x = (int) ev.getX();
int y = (int) ev.getY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
//父容器不拦截
getParent().requestDisallowInterceptTouchEvent(true);
break;
}
case MotionEvent.ACTION_MOVE: {
int deltaX = x - mLastX;
int deltaY = y - mLastY;
if(atTopOrEnd(deltaY)) {
getParent().requestDisallowInterceptTouchEvent(false);
}
break;
}
case MotionEvent.ACTION_UP: {
break;
}
default:
break;
}
mLastX = x;
mLastY = y;
return super.dispatchTouchEvent(ev);
}
//如果listView滑到顶端时当前事件向上滑动,需要scrollview接管, 在底端时类似。
private boolean atTopOrEnd(int len) {
int count = getCount();
int topId = getFirstVisiblePosition();
int endId = getLastVisiblePosition();
if((endId == count - 1 && len < 0)) {
View lastView = getChildAt(getChildCount() - 1);
if(lastView.getBottom() == getHeight()) {
return true;
}
}
if(topId == 0 && len > 0) {
View firstView = getChildAt(topId);
if(firstView.getTop() == 0) {
return true;
}
}
return false;
}
}
ViewPager의 onTouch 이벤트가 동작을 "먹었기" 때문에 ViewPager의 onTouch 이벤트를 재정의할 수 있습니다. 동작이 수직 이동인 경우 false를 반환합니다.
목록보기에서 하위 항목의 너비와 높이를 측정하는 방법을 다시 작성하려면 온라인에서 여러 번 검색하면 됩니다