在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;
}
}
Oleh kerana acara onTouch ViewPager telah "memakan" gerak isyarat, anda boleh mengatasi peristiwa onTouch ViewPager Jika gerak isyarat itu ialah pergerakan menegak, kembalikan palsu
Untuk menulis semula kaedah mengukur lebar dan tinggi sub-item dalam listview, anda boleh mencari banyak dalam talian