android - scrollView和listview滑動(dòng)沖突
問(wèn)題描述
在scrollview內(nèi)嵌套了一個(gè)viewpager,重寫(xiě)了scrollview的onInterceptTouchEvent()方法,但是我寫(xiě)的沒(méi)有什么效果,最近剛剛接觸這個(gè)滑動(dòng)沖突不能很好理解。
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)){ //點(diǎn)擊事件發(fā)生在viewpager范圍內(nèi) if(Math.abs(deltaY) > Math.abs(deltaX)) {//如果豎直方向的滑動(dòng)距離大于橫向, 那么scrollview攔截intercepted = true; } else {intercepted = false; }} else { intercepted = false;}break; } case MotionEvent.ACTION_UP: {intercepted = false;break; } default: break;}return intercepted; } //判斷點(diǎn)擊事件是否在當(dāng)前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; }}
我在紅色部分左右滑動(dòng)viewpager能夠正常,但是在viewpager中豎直滑動(dòng)就不能滾動(dòng)scrollview,但是我覺(jué)得我在scrollview的onInterceptTouchEvent()方法中已經(jīng)判斷了,但是最終卻沒(méi)有效果。
感謝采納的那位,根據(jù)他的提示, 我順便解決了listview的滑動(dòng)沖突。 現(xiàn)在使用外部攔截法: 重寫(xiě)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)){ //點(diǎn)擊事件發(fā)生在viewpager范圍內(nèi) if(Math.abs(deltaY) > Math.abs(deltaX)) {//如果豎直方向的滑動(dòng)距離大于橫向, 那么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滑到頂端時(shí)當(dāng)前事件向上滑動(dòng),需要scrollview接管, 在底端時(shí)類似。 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; } //判斷點(diǎn)擊事件是否在當(dāng)前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; }}
采用內(nèi)部攔截法: 重寫(xiě)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參數(shù)為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滑到頂端時(shí)當(dāng)前事件向上滑動(dòng),需要scrollview接管, 在底端時(shí)類似。 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; }}
問(wèn)題解答
回答1:因?yàn)閂iewPager的onTouch事件已經(jīng)“吃掉”了手勢(shì),你可以重寫(xiě)ViewPager的onTouch事件,假如手勢(shì)是豎直方向的移動(dòng),return false
回答2:要重寫(xiě)listview的測(cè)量子Item的寬高的方法,你這個(gè)網(wǎng)上搜一下很多的
相關(guān)文章:
1. docker - 各位電腦上有多少個(gè)容器啊?容器一多,自己都搞混了,咋辦呢?2. java - spring boot 如何打包成asp.net core 那種獨(dú)立應(yīng)用?3. java - 在用戶不登錄的情況下,用戶如何添加保存到購(gòu)物車(chē)?4. datetime - Python如何獲取當(dāng)前時(shí)間5. docker start -a dockername 老是卡住,什么情況?6. javascript - nginx反向代理靜態(tài)資源403錯(cuò)誤?7. docker網(wǎng)絡(luò)端口映射,沒(méi)有方便點(diǎn)的操作方法么?8. 安全性測(cè)試 - nodejs中如何防m(xù)ySQL注入9. javascript - 關(guān)于apply()與call()的問(wèn)題10. python - 調(diào)用api輸出頁(yè)面,會(huì)有標(biāo)簽出現(xiàn),請(qǐng)問(wèn)如何清掉?
