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

首頁 > 系統 > Android > 正文

android多種滑動沖突的解決方案

2019-12-12 03:47:28
字體:
來源:轉載
供稿:網友

一、前言

Android 中解決滑動的方案有2種:外部攔截法 和內部攔截法。

滑動沖突也存在2種場景: 橫豎滑動沖突、同向滑動沖突。

所以我就寫了4個例子來學習如何解決滑動沖突的,這四個例子分別為: 外部攔截法解決橫豎沖突、外部攔截法解決同向沖突、內部攔截法解決橫豎沖突、內部攔截法解決同向沖突。

先上效果圖:

二、實戰

1、外部攔截法,解決橫豎沖突

思路是,重寫父控件的onInterceptTouchEvent方法,然后根據具體的需求,來決定父控件是否攔截事件。如果攔截返回返回true,不攔截返回false。如果父控件攔截了事件,則在父控件的onTouchEvent進行相應的事件處理。

我的這個例子,是一個橫向滑動的ViewGroup里面包含了3個豎向滑動的ListView。下面我附上代碼,HorizontalEx.Java:

/** * Created by blueberry on 2016/6/20. * * 解決交錯的滑動沖突 * * 外部攔截法 */public class HorizontalEx extends ViewGroup { private static final String TAG = "HorizontalEx"; private boolean isFirstTouch = true; private int childIndex; private int childCount; private int lastXIntercept, lastYIntercept, lastX, lastY; private Scroller mScroller; private VelocityTracker mVelocityTracker; public HorizontalEx(Context context) {  super(context);  init(); } public HorizontalEx(Context context, AttributeSet attrs) {  super(context, attrs);  init(); } public HorizontalEx(Context context, AttributeSet attrs, int defStyleAttr) {  super(context, attrs, defStyleAttr);  init(); } private void init() {  mScroller = new Scroller(getContext());  mVelocityTracker = VelocityTracker.obtain(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  int width = MeasureSpec.getSize(widthMeasureSpec);  int height = MeasureSpec.getSize(heightMeasureSpec);  int widthMode = MeasureSpec.getMode(widthMeasureSpec);  int heightMode = MeasureSpec.getMode(heightMeasureSpec);  childCount = getChildCount();  measureChildren(widthMeasureSpec, heightMeasureSpec);  if (childCount == 0) {   setMeasuredDimension(0, 0);  } else if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) {   width = childCount * getChildAt(0).getMeasuredWidth();   height = getChildAt(0).getMeasuredHeight();   setMeasuredDimension(width, height);  } else if (widthMode == MeasureSpec.AT_MOST) {   width = childCount * getChildAt(0).getMeasuredWidth();   setMeasuredDimension(width, height);  } else {   height = getChildAt(0).getMeasuredHeight();   setMeasuredDimension(width, height);  } } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) {  int left = 0;  for (int i = 0; i < getChildCount(); i++) {   final View child = getChildAt(i);   child.layout(left + l, t, r + left, b);   left += child.getMeasuredWidth();  } } /**  * 攔截事件  * @param ev  * @return  */ @Override public boolean onInterceptTouchEvent(MotionEvent ev) {  boolean intercepted = false;  int x = (int) ev.getX();  int y = (int) ev.getY();  switch (ev.getAction()) {   /*如果攔截了Down事件,則子類不會拿到這個事件序列*/   case MotionEvent.ACTION_DOWN:    lastXIntercept = x;    lastYIntercept = y;    intercepted = false;    if (!mScroller.isFinished()) {     mScroller.abortAnimation();     intercepted = true;    }    break;   case MotionEvent.ACTION_MOVE:    final int deltaX = x - lastXIntercept;    final int deltaY = y - lastYIntercept;    /*根據條件判斷是否攔截該事件*/    if (Math.abs(deltaX) > Math.abs(deltaY)) {     intercepted = true;    } else {     intercepted = false;    }    break;   case MotionEvent.ACTION_UP:    intercepted = false;    break;  }  lastXIntercept = x;  lastYIntercept = y;  return intercepted; } @Override public boolean onTouchEvent(MotionEvent event) {  int x = (int) event.getX();  int y = (int) event.getY();  mVelocityTracker.addMovement(event);  ViewConfiguration configuration = ViewConfiguration.get(getContext());  switch (event.getAction()) {   case MotionEvent.ACTION_DOWN:    if (!mScroller.isFinished()) {     mScroller.abortAnimation();    }    break;   case MotionEvent.ACTION_MOVE:    /*因為這里父控件拿不到Down事件,所以使用一個布爾值,     當事件第一次來到父控件時,對lastX,lastY賦值*/    if (isFirstTouch) {     lastX = x;     lastY = y;     isFirstTouch = false;    }    final int deltaX = x - lastX;    scrollBy(-deltaX, 0);    break;   case MotionEvent.ACTION_UP:    int scrollX = getScrollX();    final int childWidth = getChildAt(0).getWidth();    mVelocityTracker.computeCurrentVelocity(1000, configuration.getScaledMaximumFlingVelocity());    float xVelocity = mVelocityTracker.getXVelocity();    if (Math.abs(xVelocity) > configuration.getScaledMinimumFlingVelocity()) {     childIndex = xVelocity < 0 ? childIndex + 1 : childIndex - 1;    } else {     childIndex = (scrollX + childWidth / 2) / childWidth;    }    childIndex = Math.min(getChildCount() - 1, Math.max(childIndex, 0));    smoothScrollBy(childIndex * childWidth - scrollX, 0);    mVelocityTracker.clear();    isFirstTouch = true;    break;  }  lastX = x;  lastY = y;  return true; } void smoothScrollBy(int dx, int dy) {  mScroller.startScroll(getScrollX(), getScrollY(), dx, dy, 500);  invalidate(); } @Override public void computeScroll() {  if (mScroller.computeScrollOffset()) {   scrollTo(mScroller.getCurrX(), mScroller.getCurrY());   invalidate();  } } @Override protected void onDetachedFromWindow() {  super.onDetachedFromWindow();  mVelocityTracker.recycle(); }}

調用代碼:

@Override public void showOutHVData(List<String> data1, List<String> data2, List<String> data3) {  ListView listView1 = new ListView(getContext());  ArrayAdapter<String> adapter1 = new ArrayAdapter<String>(getContext(), android.R.layout.simple_list_item_1, data1);  listView1.setAdapter(adapter1);  ListView listView2 = new ListView(getContext());  ArrayAdapter<String> adapter2 = new ArrayAdapter<String>(getContext(), android.R.layout.simple_list_item_1, data2);  listView2.setAdapter(adapter2);  ListView listView3 = new ListView(getContext());  ArrayAdapter<String> adapter3 = new ArrayAdapter<String>(getContext(), android.R.layout.simple_list_item_1, data3);  listView3.setAdapter(adapter3);  ViewGroup.LayoutParams params    = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,    ViewGroup.LayoutParams.MATCH_PARENT);  mHorizontalEx.addView(listView1, params);  mHorizontalEx.addView(listView2, params);  mHorizontalEx.addView(listView3, params); }

其實外部攔截的主要思想都在于對onInterceptTouchEvent的重寫。

@Override public boolean onInterceptTouchEvent(MotionEvent ev) {  boolean intercepted = false;  int x = (int) ev.getX();  int y = (int) ev.getY();  switch (ev.getAction()) {   /*如果攔截了Down事件,則子類不會拿到這個事件序列*/   case MotionEvent.ACTION_DOWN:    lastXIntercept = x;    lastYIntercept = y;    intercepted = false;    if (!mScroller.isFinished()) {     mScroller.abortAnimation();     intercepted = true;    }    break;   case MotionEvent.ACTION_MOVE:    final int deltaX = x - lastXIntercept;    final int deltaY = y - lastYIntercept;    /*根據條件判斷是否攔截該事件*/    if (Math.abs(deltaX) > Math.abs(deltaY)) {     intercepted = true;    } else {     intercepted = false;    }    break;   case MotionEvent.ACTION_UP:    intercepted = false;    break;  }  lastXIntercept = x;  lastYIntercept = y;  return intercepted; }

這幾乎是一個實現外部攔截事件的模板,這里一定不要在ACTION_DOWN 中返回 true,否則會讓子VIew沒有機會得到事件,因為如果在ACTION_DOWN的時候返回了 true,同一個事件序列ViewGroup的disPatchTouchEvent就不會在調用onInterceptTouchEvent方法了。

還有就是 在ACTION_UP中返回false,因為如果父控件攔截了ACTION_UP,那么子View將得不到UP事件,那么將會影響子View的 Onclick方法等。但這對父控件是沒有影響的,因為如果是父控件子ACITON_MOVE中 就攔截了事件,他們UP事件必定也會交給它處理,因為有那么一條定律叫做:父控件一但攔截了事件,那么同一個事件序列的所有事件都將交給他處理。這條結論在我的上一篇文章中已經分析過。

最后就是在 ACTION_MOVE中根據需求決定是否攔截。

2、內部攔截法,解決橫豎沖突

內部攔截主要依賴于父控件的 requestDisallowInterceptTouchEvent方法,關于這個方法我的上篇文章其實已經分析過。他設置父控件的一個標志(FLAG_DISALLOW_INTERCEPT)

這個標志可以決定父控件是否攔截事件,如果設置了這個標志則不攔截,如果沒設這個標志,它就會調用父控件的onInterceptTouchEvent()來詢問父控件是否攔截。但這個標志對Down事件無效。

可以參考一下源碼:   

 // Handle an initial down.   if (actionMasked == MotionEvent.ACTION_DOWN) {    // Throw away all previous state when starting a new touch gesture.    // The framework may have dropped the up or cancel event for the previous gesture    // due to an app switch, ANR, or some other state change.    cancelAndClearTouchTargets(ev);    //清楚標志    resetTouchState();   }   // Check for interception.   final boolean intercepted;   if (actionMasked == MotionEvent.ACTION_DOWN     || mFirstTouchTarget != null) {     //標志    final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;    if (!disallowIntercept) {     intercepted = onInterceptTouchEvent(ev);     ev.setAction(action); // restore action in case it was changed    } else {     intercepted = false;    }   } else {    // There are no touch targets and this action is not an initial down    // so this view group continues to intercept touches.    intercepted = true;   }

那么我們如果想使用 內部攔截法攔截事件。

第一步:

a、我們要重寫父控件的onInterceptTouchEvent,在ACTION_DOWN的時候返回false,負責的話子View調用requestDisallowInterceptTouchEvent也將無能為力。

b、還有就是其他事件的話都返回true,這樣就把能否攔截事件的權利交給了子View。

第二步:

在子View的dispatchTouchEvent中 來決定是否讓父控件攔截事件。

a. 先要在MotionEvent.ACTION_DOWN:的時候使用mHorizontalEx2.requestDisallowInterceptTouchEvent(true);,負責的話,下一個事件到來時,就交給父控件了。

b. 然后在MotionEvent.ACTION_MOVE: 根據業務邏輯決定是否調用mHorizontalEx2.requestDisallowInterceptTouchEvent(false);來決定父控件是否攔截事件。

上代碼HorizontalEx2.java:

/** * Created by blueberry on 2016/6/20. * 內部攔截 * 和 ListViewEx配合使用 */public class HorizontalEx2 extends ViewGroup { private int lastX, lastY; private int childIndex; private Scroller mScroller; private VelocityTracker mVelocityTracker; public HorizontalEx2(Context context) {  super(context);  init(); } public HorizontalEx2(Context context, AttributeSet attrs) {  super(context, attrs);  init(); } public HorizontalEx2(Context context, AttributeSet attrs, int defStyleAttr) {  super(context, attrs, defStyleAttr);  init(); } private void init() {  mScroller = new Scroller(getContext());  mVelocityTracker = VelocityTracker.obtain(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  int width = MeasureSpec.getSize(widthMeasureSpec);  int widthMode = MeasureSpec.getMode(widthMeasureSpec);  int height = MeasureSpec.getSize(heightMeasureSpec);  int heightMode = MeasureSpec.getMode(heightMeasureSpec);  int childCount = getChildCount();  measureChildren(widthMeasureSpec, heightMeasureSpec);  if (childCount == 0) {   setMeasuredDimension(0, 0);  } else if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) {   height = getChildAt(0).getMeasuredHeight();   width = childCount * getChildAt(0).getMeasuredWidth();   setMeasuredDimension(width, height);  } else if (widthMode == MeasureSpec.AT_MOST) {   width = childCount * getChildAt(0).getMeasuredWidth();   setMeasuredDimension(width, height);  } else {   height = getChildAt(0).getMeasuredHeight();   setMeasuredDimension(width, height);  } } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) {  int leftOffset = 0;  for (int i = 0; i < getChildCount(); i++) {   View child = getChildAt(i);   child.layout(l + leftOffset, t, r + leftOffset, b);   leftOffset += child.getMeasuredWidth();  } } /**  * 不攔截Down事件,其他一律攔截  * @param ev  * @return  */ @Override public boolean onInterceptTouchEvent(MotionEvent ev) {  if (ev.getAction() == MotionEvent.ACTION_DOWN) {   if (!mScroller.isFinished()) {    mScroller.abortAnimation();    return true;   }   return false;  } else {   return true;  } } private boolean isFirstTouch = true; @Override public boolean onTouchEvent(MotionEvent event) {  int x = (int) event.getX();  int y = (int) event.getY();  mVelocityTracker.addMovement(event);  ViewConfiguration configuration = ViewConfiguration.get(getContext());  switch (event.getAction()) {   case MotionEvent.ACTION_DOWN:    if (!mScroller.isFinished()) {     mScroller.abortAnimation();    }    break;   case MotionEvent.ACTION_MOVE:    if (isFirstTouch) {     isFirstTouch = false;     lastY = y;     lastX = x;    }    final int deltaX = x - lastX;    scrollBy(-deltaX, 0);    break;   case MotionEvent.ACTION_UP:    isFirstTouch = true;    int scrollX = getScrollX();    mVelocityTracker.computeCurrentVelocity(1000, configuration.getScaledMaximumFlingVelocity());    float mVelocityX = mVelocityTracker.getXVelocity();    if (Math.abs(mVelocityX) > configuration.getScaledMinimumFlingVelocity()) {     childIndex = mVelocityX < 0 ? childIndex + 1 : childIndex - 1;    } else {     childIndex = (scrollX + getChildAt(0).getWidth() / 2) / getChildAt(0).getWidth();    }    childIndex = Math.min(getChildCount() - 1, Math.max(0, childIndex));    smoothScrollBy(childIndex*getChildAt(0).getWidth()-scrollX,0);    mVelocityTracker.clear();    break;  }  lastX = x;  lastY = y;  return true; } private void smoothScrollBy(int dx, int dy) {  mScroller.startScroll(getScrollX(), getScrollY(), dx, dy,500);  invalidate(); } @Override public void computeScroll() {  if(mScroller.computeScrollOffset()){   scrollTo(mScroller.getCurrX(),mScroller.getCurrY());   postInvalidate();  } } @Override protected void onDetachedFromWindow() {  super.onDetachedFromWindow();  mVelocityTracker.recycle(); }}

ListViewEx.java

/** * 內部攔截事件 */public class ListViewEx extends ListView { private int lastXIntercepted, lastYIntercepted; private HorizontalEx2 mHorizontalEx2; 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); } public HorizontalEx2 getmHorizontalEx2() {  return mHorizontalEx2; } public void setmHorizontalEx2(HorizontalEx2 mHorizontalEx2) {  this.mHorizontalEx2 = mHorizontalEx2; } /**  * 使用 outter.requestDisallowInterceptTouchEvent();  * 來決定父控件是否對事件進行攔截  * @param ev  * @return  */ @Override public boolean dispatchTouchEvent(MotionEvent ev) {  int x = (int) ev.getX();  int y = (int) ev.getY();  switch (ev.getAction()) {   case MotionEvent.ACTION_DOWN:    mHorizontalEx2.requestDisallowInterceptTouchEvent(true);    break;   case MotionEvent.ACTION_MOVE:    final int deltaX = x-lastYIntercepted;    final int deltaY = y-lastYIntercepted;    if(Math.abs(deltaX)>Math.abs(deltaY)){     mHorizontalEx2.requestDisallowInterceptTouchEvent(false);    }    break;   case MotionEvent.ACTION_UP:    break;  }  lastXIntercepted = x;  lastYIntercepted = y;  return super.dispatchTouchEvent(ev); }}

調用代碼:

 @Override public void showInnerHVData(List<String> data1, List<String> data2, List<String> data3) {  ListViewEx listView1 = new ListViewEx(getContext());  ArrayAdapter<String> adapter1 = new ArrayAdapter<String>(getContext(), android.R.layout.simple_list_item_1, data1);  listView1.setAdapter(adapter1);  listView1.setmHorizontalEx2(mHorizontalEx2);  ListViewEx listView2 = new ListViewEx(getContext());  ArrayAdapter<String> adapter2 = new ArrayAdapter<String>(getContext(), android.R.layout.simple_list_item_1, data2);  listView2.setAdapter(adapter2);  listView2.setmHorizontalEx2(mHorizontalEx2);  ListViewEx listView3 = new ListViewEx(getContext());  ArrayAdapter<String> adapter3 = new ArrayAdapter<String>(getContext(), android.R.layout.simple_list_item_1, data3);  listView3.setAdapter(adapter3);  listView3.setmHorizontalEx2(mHorizontalEx2);  ViewGroup.LayoutParams params    = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,    ViewGroup.LayoutParams.MATCH_PARENT);  mHorizontalEx2.addView(listView1, params);  mHorizontalEx2.addView(listView2, params);  mHorizontalEx2.addView(listView3, params); }

至此,2種攔截方法已經學習完畢,下面我們來學習如何解決同向滑動沖突。

其實和上面的2個例子思路是一樣的,只是用來判斷是否攔截的那塊邏輯不同而已。

下面的例子,是一個下拉刷新的一個控件。

3、外部攔截 解決同向滑動沖突

RefreshLayoutBase.java

package com.blueberry.sample.widget.refresh;import android.content.Context;import android.graphics.Color;import android.util.AttributeSet;import android.util.DisplayMetrics;import android.util.Log;import android.util.TypedValue;import android.view.MotionEvent;import android.view.View;import android.view.ViewConfiguration;import android.view.ViewGroup;import android.view.WindowManager;import android.widget.ProgressBar;import android.widget.Scroller;import android.widget.TextView;import com.blueberry.sample.R;/** *外部攔截(同向) * */public abstract class RefreshLayoutBase<T extends View> extends ViewGroup { private static final String TAG = "RefreshLayoutBase"; public static final int STATUS_LOADING = 1; public static final int STATUS_RELEASE_TO_REFRESH = 2; public static final int STATUS_PULL_TO_REFRESH = 3; public static final int STATUS_IDLE = 4; public static final int STATUS_LOAD_MORE =5; private static int SCROLL_DURATION =500; protected ViewGroup mHeadView; protected ViewGroup mFootView; private T contentView; private ProgressBar headProgressBar; private TextView headTv; private ProgressBar footProgressBar; private TextView footTv; private boolean isFistTouch = true; protected int currentStatus = STATUS_IDLE; private int mScreenWidth; private int mScreenHeight; private int mLastXIntercepted; private int mLastYIntercepted; private int mLastX; private int mLastY; protected int mInitScrollY = 0; private int mTouchSlop; protected Scroller mScoller; private OnRefreshListener mOnRefreshListener; public RefreshLayoutBase(Context context) {  this(context, null); } public RefreshLayoutBase(Context context, AttributeSet attrs) {  this(context, attrs, 0); } public RefreshLayoutBase(Context context, AttributeSet attrs, int defStyleAttr) {  super(context, attrs, defStyleAttr);  getScreenSize();  initView();  mScoller = new Scroller(context);  mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();  setPadding(0, 0, 0, 0); } public void setContentView(T view) {  addView(view, 1); } public OnRefreshListener getOnRefreshListener() {  return mOnRefreshListener; } public void setOnRefreshListener(OnRefreshListener mOnRefreshListener) {  this.mOnRefreshListener = mOnRefreshListener; } private void initView() {  setupHeadView();  setupFootView(); } private void getScreenSize() {  WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);  DisplayMetrics metrics = new DisplayMetrics();  wm.getDefaultDisplay().getMetrics(metrics);  mScreenWidth = metrics.widthPixels;  mScreenHeight = metrics.heightPixels; } private int dp2px(int dp) {  WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);  DisplayMetrics metrics = new DisplayMetrics();  wm.getDefaultDisplay().getMetrics(metrics);  return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, metrics); } /**  * 設置頭布局  */ private void setupHeadView() {  mHeadView = (ViewGroup) View.inflate(getContext(), R.layout.fresh_head_view, null);  mHeadView.setBackgroundColor(Color.RED);  headProgressBar = (ProgressBar) mHeadView.findViewById(R.id.head_progressbar);  headTv = (TextView) mHeadView.findViewById(R.id.head_tv);  /*設置 實際高度為 1/4 ,但內容區域只有 100dp*/  ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, mScreenHeight / 4);  mHeadView.setLayoutParams(layoutParams);  mHeadView.setPadding(0, mScreenHeight / 4 - dp2px(100), 0, 0);  addView(mHeadView); } /**  * 設置尾布局  */ private void setupFootView() {  mFootView = (ViewGroup) View.inflate(getContext(), R.layout.fresh_foot_view, null);  mFootView.setBackgroundColor(Color.BLUE);  footProgressBar = (ProgressBar) mFootView.findViewById(R.id.fresh_foot_progressbar);  footTv = (TextView) mFootView.findViewById(R.id.fresh_foot_tv);  addView(mFootView); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  int widthSize = MeasureSpec.getSize(widthMeasureSpec);  int widthMode = MeasureSpec.getMode(widthMeasureSpec);  int height = MeasureSpec.getSize(heightMeasureSpec);  int heightMode = MeasureSpec.getMode(heightMeasureSpec);  int finalHeight = 0;  for (int i = 0; i < getChildCount(); i++) {   View child = getChildAt(i);   measureChild(child, widthMeasureSpec, heightMeasureSpec);   finalHeight += child.getMeasuredHeight();  }  if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) {   widthSize = getChildAt(0).getMeasuredWidth();   setMeasuredDimension(widthSize, finalHeight);  } else if (widthMode == MeasureSpec.AT_MOST) {   widthSize = getChildAt(0).getMeasuredWidth();   setMeasuredDimension(widthSize, height);  } else {   setMeasuredDimension(widthSize, finalHeight);  } } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) {  int topOffset = 0;  for (int i = 0; i < getChildCount(); i++) {   View child = getChildAt(i);   child.layout(getPaddingLeft(), getPaddingTop() + topOffset, r, getPaddingTop() + child.getMeasuredHeight() + topOffset);   topOffset += child.getMeasuredHeight();  }  mInitScrollY = mHeadView.getMeasuredHeight() + getPaddingTop();  scrollTo(0, mInitScrollY); } @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:    mLastXIntercepted = x;    mLastYIntercepted = y;    break;   case MotionEvent.ACTION_MOVE:    final int deltaY = x - mLastYIntercepted;    if (isTop() && deltaY > 0 && Math.abs(deltaY) > mTouchSlop) {     /*下拉*/     intercepted = true;    }    break;   case MotionEvent.ACTION_UP:    break;  }  mLastXIntercepted = x;  mLastYIntercepted = y;  return intercepted; } private void doRefresh() {  Log.i(TAG, "doRefresh: ");  if (currentStatus == STATUS_RELEASE_TO_REFRESH) {   mScoller.startScroll(0, getScrollY(), 0, mInitScrollY - getScrollY(), SCROLL_DURATION);   currentStatus = STATUS_IDLE;  } else if (currentStatus == STATUS_PULL_TO_REFRESH) {   mScoller.startScroll(0,getScrollY(),0,0-getScrollY(),SCROLL_DURATION);   if (null != mOnRefreshListener) {    currentStatus = STATUS_LOADING;    mOnRefreshListener.refresh();   }  }  invalidate(); } @Override public boolean onTouchEvent(MotionEvent event) {  int x = (int) event.getX();  int y = (int) event.getY();  switch (event.getAction()) {   case MotionEvent.ACTION_DOWN:    if (!mScoller.isFinished()) {     mScoller.abortAnimation();    }    mLastX = x;    mLastY = y;    break;   case MotionEvent.ACTION_MOVE:    if (isFistTouch) {     isFistTouch = false;     mLastX = x;     mLastY = y;    }    final int deltaY = y - mLastY;    if (currentStatus != STATUS_LOADING) {     changeScrollY(deltaY);    }    break;   case MotionEvent.ACTION_UP:    isFistTouch = true;    doRefresh();    break;  }  mLastX = x;  mLastY = y;  return true; } private void changeScrollY(int deltaY) {  Log.i(TAG, "changeScrollY: ");  int curY = getScrollY();  if (deltaY > 0) {   /*下拉*/   if (curY - deltaY > getPaddingTop()) {    scrollBy(0, -deltaY);   }  } else {   /*上拉*/   if (curY - deltaY <= mInitScrollY) {    scrollBy(0, -deltaY);   }  }  curY = getScrollY();  int slop = mInitScrollY / 2;  if (curY > 0 && curY <=slop) {   currentStatus = STATUS_PULL_TO_REFRESH;  } else if (curY > 0 && curY >= slop) {   currentStatus = STATUS_RELEASE_TO_REFRESH;  } } @Override public void computeScroll() {  if (mScoller.computeScrollOffset()) {   scrollTo(mScoller.getCurrX(), mScoller.getCurrY());   postInvalidate();  } } /**  * 加載完成調用這個方法  */ public void refreshComplete() {  mScoller.startScroll(0, getScrollY(), 0, mInitScrollY - getScrollY(), SCROLL_DURATION);  currentStatus = STATUS_IDLE;  invalidate(); } /**  * 顯示 Footer  */ public void showFooter() {  if(currentStatus==STATUS_LOAD_MORE) return ;  currentStatus = STATUS_LOAD_MORE ;  mScoller.startScroll(0, getScrollY(), 0, mFootView.getMeasuredHeight()    , SCROLL_DURATION);  invalidate(); } /**  * loadMore完成之后調用  */ public void footerComplete() {  mScoller.startScroll(0, getScrollY(), 0, mInitScrollY - getScrollY(), SCROLL_DURATION);  invalidate();  currentStatus = STATUS_IDLE; } public interface OnRefreshListener {  void refresh(); } abstract boolean isTop(); abstract boolean isBottom();}

它是一個抽象類,需要編寫子類繼承isTop()和 isBottom()方法。下面給出它的一個實現類:

package com.blueberry.sample.widget.refresh;import android.content.Context;import android.util.AttributeSet;import android.widget.AbsListView;import android.widget.ListView;/** * Created by blueberry on 2016/6/21. * * RefreshLayoutBase 的一個實現類 */public class RefreshListView extends RefreshLayoutBase<ListView> { private static final String TAG = "RefreshListView"; private ListView listView; private OnLoadListener loadListener; public RefreshListView(Context context) {  super(context); } public RefreshListView(Context context, AttributeSet attrs) {  super(context, attrs); } public RefreshListView(Context context, AttributeSet attrs, int defStyleAttr) {  super(context, attrs, defStyleAttr); } public ListView getListView() {  return listView; } public void setListView(final ListView listView) {  this.listView = listView;  setContentView(listView);  this.listView.setOnScrollListener(new AbsListView.OnScrollListener() {   @Override   public void onScrollStateChanged(AbsListView view, int scrollState) {   }   @Override   public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {    /*這里存在一個bug: 當listView滑動到底部的時候,如果下拉也會出現footer    * 這是因為,暫時還沒有想到如何判斷是下拉還是上拉。    * 如果要解決此問題,我覺得應該重寫listView 的onTouchEvent來判斷手勢方向    * 次模塊主要解決豎向滑動沖突,故現將此問題放下。    * */    if (currentStatus == STATUS_IDLE      && getScrollY() <= mInitScrollY && isBottom()      ) {     showFooter();     if (null != loadListener) {      loadListener.onLoadMore();     }    }   }  }); } public OnLoadListener getLoadListener() {  return loadListener; } public void setLoadListener(OnLoadListener loadListener) {  this.loadListener = loadListener; } @Override boolean isTop() {  return listView.getFirstVisiblePosition() == 0    && getScrollY() <= mHeadView.getMeasuredHeight(); } @Override boolean isBottom() {  return listView.getLastVisiblePosition() == listView.getAdapter().getCount() - 1; } public interface OnLoadListener {  void onLoadMore(); }}

4、內部攔截法解決同向滑動

同樣是一個下拉刷新組件,因為實現原理都一樣,所以這個寫的比較隨意些。主要還是如果解決滑動沖突。

RefreshLayoutBase2.java

package com.blueberry.sample.widget.refresh;import android.content.Context;import android.graphics.Color;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.widget.ArrayAdapter;import android.widget.ListView;import android.widget.Scroller;import com.blueberry.sample.R;import java.util.ArrayList;import java.util.List;/** * Created by blueberry on 2016/6/22. * 結合內部類 ListVieEx * 內部攔截法,同向 */public class RefreshLayoutBase2 extends ViewGroup { private static final String TAG = "RefreshLayoutBase2"; private static List<String> datas; static {  datas = new ArrayList<>();  for (int i = 0; i < 40; i++) {   datas.add("數據―" + i);  } } private ViewGroup headView; private ListViewEx lv; private int lastY; public int mInitScrollY; private Scroller mScroller; public RefreshLayoutBase2(Context context) {  this(context, null); } public RefreshLayoutBase2(Context context, AttributeSet attrs) {  this(context, attrs, 0); } public RefreshLayoutBase2(Context context, AttributeSet attrs, int defStyleAttr) {  super(context, attrs, defStyleAttr);  mScroller = new Scroller(context);  setupHeadView(context);  setupContentView(context); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  int widthSize = MeasureSpec.getSize(widthMeasureSpec);  int widthMode = MeasureSpec.getMode(widthMeasureSpec);  int height = MeasureSpec.getSize(heightMeasureSpec);  int heightMode = MeasureSpec.getMode(heightMeasureSpec);  int finalHeight = 0;  for (int i = 0; i < getChildCount(); i++) {   View child = getChildAt(i);   measureChild(child, widthMeasureSpec, heightMeasureSpec);   finalHeight += child.getMeasuredHeight();  }  if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) {   widthSize = getChildAt(0).getMeasuredWidth();   setMeasuredDimension(widthSize, finalHeight);  } else if (widthMode == MeasureSpec.AT_MOST) {   widthSize = getChildAt(0).getMeasuredWidth();   setMeasuredDimension(widthSize, height);  } else {   setMeasuredDimension(widthSize, finalHeight);  } } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) {  int topOffset = 0;  for (int i = 0; i < getChildCount(); i++) {   View child = getChildAt(i);   child.layout(getPaddingLeft(), getPaddingTop() + topOffset, r, getPaddingTop() + child.getMeasuredHeight() + topOffset);   topOffset += child.getMeasuredHeight();  }  mInitScrollY = headView.getMeasuredHeight() + getPaddingTop();  scrollTo(0, mInitScrollY); } /**  * 不攔截Down 其他一律攔截  * @param ev  * @return  */ @Override public boolean onInterceptTouchEvent(MotionEvent ev) {  if (ev.getAction() == MotionEvent.ACTION_DOWN) return false;  return true; } @Override public boolean onTouchEvent(MotionEvent event) {  int y = (int) event.getY();  switch (event.getAction()) {   case MotionEvent.ACTION_DOWN:    break;   case MotionEvent.ACTION_MOVE:    final int deltaY = y-lastY;    Log.i(TAG, "onTouchEvent: deltaY: "+deltaY);    if (deltaY >= 0 && lv.isTop() && getScrollY() - deltaY >=getPaddingTop()) {      scrollBy(0, -deltaY);    }    break;   case MotionEvent.ACTION_UP:    this.postDelayed(new Runnable() {     @Override     public void run() {      mScroller.startScroll(0,getScrollY(),0,mInitScrollY-getScrollY());      invalidate();     }    },2000);    break;  }  lastY = y ;  return true; } private void setupHeadView(Context context) {  headView = (ViewGroup) View.inflate(context, R.layout.fresh_head_view, null);  headView.setBackgroundColor(Color.RED);  ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 300);  addView(headView, params); } public void setupContentView(Context context) {  lv = new ListViewEx(context, this);  lv.setBackgroundColor(Color.BLUE);  ArrayAdapter<String> adapter = new ArrayAdapter<String>(getContext(), android.R.layout.simple_list_item_1, datas);  lv.setAdapter(adapter);  addView(lv, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); } @Override public void computeScroll() {  if(mScroller.computeScrollOffset()){   scrollTo(mScroller.getCurrX(),mScroller.getCurrY());   postInvalidate();  } } public static class ListViewEx extends ListView {  private RefreshLayoutBase2 outter;  public ListViewEx(Context context, RefreshLayoutBase2 outter) {   super(context);   this.outter = outter;  }  public ListViewEx(Context context, AttributeSet attrs) {   super(context, attrs);  }  public ListViewEx(Context context, AttributeSet attrs, int defStyleAttr) {   super(context, attrs, defStyleAttr);  }  /**   * 使用 outter.requestDisallowInterceptTouchEvent();   * 來決定父控件是否對事件進行攔截   * @param ev   * @return   */  @Override  public boolean dispatchTouchEvent(MotionEvent ev) {   switch (ev.getAction()) {    case MotionEvent.ACTION_DOWN:     outter.requestDisallowInterceptTouchEvent(true);     break;    case MotionEvent.ACTION_MOVE:     if ( isTop() && outter.getScrollY() <= outter.mInitScrollY) {      outter.requestDisallowInterceptTouchEvent(false);     }     break;   }   return super.dispatchTouchEvent(ev);  }  public boolean isTop() {   return getFirstVisiblePosition() ==0;  } }}

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

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 海林市| 平潭县| 恩施市| 龙胜| 任丘市| 四平市| 土默特左旗| 枝江市| 静海县| 高雄县| 曲周县| 武宣县| 南涧| 湖北省| 曲沃县| 秦安县| 东海县| 独山县| 丽江市| 黔西| 公主岭市| 汤阴县| 正宁县| 昆明市| 莱西市| 南部县| 乐东| 武川县| 特克斯县| 新昌县| 罗江县| 宁化县| 嘉善县| 桐柏县| 石首市| 綦江县| 邻水| 武威市| 泊头市| 应城市| 郓城县|