国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android滑動事件沖突的解決方法

2019-12-12 03:30:27
字體:
來源:轉載
供稿:網友

滑動是Android中不可缺少的一部分,多個滑動必然會產生沖突,比如我們最常見的是ScrollView中嵌套了ListView,一般做法是計算出ListView的總高度,這樣就不用去滑動ListView了。又比如一個ViewPager嵌套Fragment,Fragment里面又有ListView,這原本是有滑動沖突的,但是ViewPager內部去幫我們解決了這種沖突。那如果我們要自己解決沖突又該怎么辦呢。

下面有兩種方式來解決:

外部攔截法
外部攔截法是指在有點擊事件時都要經過父容器,那么在父容器時如果需要攔截就攔截自己處理,不需要則傳遞給下一層進行處理,下面看個例子:

首先定義一個水平滑動的HorizontalScrollViewEx,看主要代碼

主要的攔截是需要重寫onInterceptTouchEvent

@Override  public boolean onInterceptTouchEvent(MotionEvent ev) {  boolean intercepted = false;  int x = (int) ev.getX();  int y = (int) ev.getY();  switch (ev.getAction()) {  case MotionEvent.ACTION_DOWN:  //down事件不攔截,否則無法傳給子元素  intercepted = false;  if (!mScroller.isFinished()) {   mScroller.abortAnimation();   intercepted = true;  }  break;  case MotionEvent.ACTION_MOVE:  int deltaX = x - mLastXIntercept;  int deltaY = y - mLastYIntercept;  //水平滑動則攔截  if (Math.abs(deltaX) > Math.abs(deltaY) + 5) {   intercepted = true;  } else {   intercepted = false;  }  break;  case MotionEvent.ACTION_UP:  //不攔截,否則子元素無法收到  intercepted = false;  break;  }  //因為當ViewGroup中的子View可能消耗了down事件,在onTouchEvent無法獲取,  // 無法對mLastX賦初值,所以在這里賦值一次  mLastX = x;  mLastY = y;  mLastYIntercept = y;  mLastXIntercept = x;  return intercepted;  } 

在down事件不需要攔截,返回false,否則的話子view無法收到事件,將全部會由父容器處理,這不是希望的;up事件也要返回false,否則最后子view收不到。

看看move事件,當水平滑動距離大于豎直距離時,代表水平滑動,返回true,由父類來進行處理,否則交由子view處理。這里move事件就是主要的攔截條件判斷,如果你遇到的不是水平和豎直的條件這么簡單,就可以在這里進行改變,比如,ScrollView嵌套了ListView,條件就變成,當ListView滑動到底部或頂部時,返回true,交由父類滑動處理,否則自身ListView滑動。

在onTouchEvent中主要是做的滑動切換的處理

@Override  public boolean onTouchEvent(MotionEvent event) {  mVelocityTracker.addMovement(event);  int x = (int) event.getX();  int y = (int) event.getY();  switch (event.getAction()) {  case MotionEvent.ACTION_DOWN:  if (!mScroller.isFinished()) {   mScroller.abortAnimation();  }  break;  case MotionEvent.ACTION_MOVE:  int deltaX = x - mLastX;  int deltaY = y - mLastY;  if (getScrollX() < 0) {   scrollTo(0, 0);  }  scrollBy(-deltaX, 0);  break;  case MotionEvent.ACTION_UP:  int scrollX = getScrollX();  mVelocityTracker.computeCurrentVelocity(1000);  float xVelocityTracker = mVelocityTracker.getXVelocity();  if (Math.abs(xVelocityTracker) > 50) {//速度大于50則滑動到下一個   mChildIndex = xVelocityTracker > 0 ? mChildIndex - 1 : mChildIndex + 1;  } else {   mChildIndex = (scrollX + mChildWith / 2) / mChildWith;  }  mChildIndex = Math.max(0, Math.min(mChildIndex, mChildrenSize - 1));  int dx = mChildIndex * mChildWith - scrollX;  smoothScrollBy(dx, 0);  mVelocityTracker.clear();  break;  }  mLastY = y;  mLastX = x;  return true;  } 

在這個嵌套一個普通的ListView,這樣就可以解決水平和豎直滑動沖突的問題了。

<com.example.lzy.customview.HorizontalScrollViewEx  android:layout_width="match_parent"  android:layout_height="200dp">   <ListView  android:id="@+id/listView"  android:layout_width="match_parent"  android:layout_height="match_parent" />   <Button  android:layout_width="match_parent"  android:layout_height="match_parent"  android:background="@android:color/holo_blue_bright"  android:text="2" />   <Button  android:layout_width="match_parent"  android:layout_height="match_parent"  android:background="@android:color/holo_green_dark"  android:text="3" />  </com.example.lzy.customview.HorizontalScrollViewEx> 

其他的部分代碼如果需要可以下載源碼來看

內部攔截法

內部攔截法是父容器不攔截任何事件,所有事件都傳遞給子view,如果需要就直接消耗掉,不需要再傳給父容器處理

下面重寫一個ListView,只需要重寫一個dispatchTouchEvent方法就OK

public class ListViewEx extends ListView {   private static final String TAG = "lzy";  private int mLastX;  private int mLastY;   public ListViewEx(Context context) {  super(context);  }   public ListViewEx(Context context, AttributeSet attrs) {  super(context, attrs);  }   public ListViewEx(Context context, AttributeSet attrs, int defStyleAttr) {  super(context, attrs, defStyleAttr);  }    @Override  public boolean dispatchTouchEvent(MotionEvent ev) {  int x = (int) ev.getX();  int y = (int) ev.getY();   switch (ev.getAction()) {  case MotionEvent.ACTION_DOWN:  //子View的所有父ViewGroup都會跳過onInterceptTouchEvent的回調  getParent().requestDisallowInterceptTouchEvent(true);  break;  case MotionEvent.ACTION_MOVE:  int deltaX = x - mLastX;  int deltaY = y - mLastY;  if (Math.abs(deltaX) > Math.abs(deltaY) + 5) {//水平滑動,使得父類可以執行onInterceptTouchEvent   getParent().requestDisallowInterceptTouchEvent(false);  }  break;  }  mLastX = x;  mLastY = y;  return super.dispatchTouchEvent(ev);  } } 

在down事件調用getParent().requestDisallowInterceptTouchEvent(true),這句代碼的意思是使這個view的父容器都會跳過onInterceptTouchEvent,在move中判斷如果是水平滑動就由父容器去處理,父容器只需要把之前的onInterceptTouchEvent改為下面那樣,其他不變。

@Override  public boolean onInterceptTouchEvent(MotionEvent ev) {  int x = (int) ev.getX();  int y = (int) ev.getY();  if (ev.getAction() == MotionEvent.ACTION_DOWN) {  mLastX = x;  mLastY = y;  if (!mScroller.isFinished()) {  mScroller.abortAnimation();  return true;  }  return false;  } else {  //如果是非down事件,說明子View并沒有攔截父類的onInterceptTouchEvent  //說明該事件交由父類處理,所以不需要再傳遞給子類,返回true  return true;  }  } 

最終實現效果就是下面那樣,兩個是用兩種方式實現的,上面的圓圈是一個簡單的自定義View練習

下載地址:Android滑動事件沖突

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 象州县| 馆陶县| 应城市| 仪征市| 虞城县| 深州市| 饶河县| 克什克腾旗| 灌云县| 河北省| 孟州市| 大埔县| 广南县| 海门市| 宝清县| 延长县| 旌德县| 班玛县| 黔西| 永胜县| 鱼台县| 武鸣县| 铜陵市| 封丘县| 同德县| 安吉县| 临高县| 喜德县| 浑源县| 奈曼旗| 怀仁县| 新晃| 杭锦后旗| 绍兴市| 察隅县| 五指山市| 兴和县| 吴江市| 铁力市| 建湖县| 青川县|