项目Github链接:https://github.com/licaomeng/Android-PullToRefresh-SwipeMenuListView-Sample

如果项目对您有帮助,欢迎小伙伴们在github上Star我的项目~

PullToRefresh是一个非常完美的下拉刷新的开源项目,SwipeMenuListView是一个向左滑动ListView中item实现可以删除功能的开源项目。笔者在此将两套开源项目整合形成一套,类似于手机qq那样同时支持下拉刷新和向左滑动的列表。效果如下:


两套框架整合的关键在于对Touch事件处理的把握,Touch事件的处理主要由Action_Down, Action_Move,Action_Up组成。Action_Down表示用户按下屏幕的操作,Action_Up表示用户按下屏幕后抬起的操作,Action_Move表示用户在屏幕上的移动操作。Touch事件处理流程图如下:


1.当ACTION_UP事件生效的时候,判断如果是下拉操作,执行onRefresh(), 实现下拉刷新,然后执行resetHeaderHeight()恢复Header的高度;判断如果是上拉操作,当mFooterView的高度大于自定义的高度,那么就执行startLoadMore()加载更多,然后执行resetFooterHeight()恢复Footer的高度。判断如果是侧滑那么就结束SwipeMenu的滑动。

2.当ACTION_MOVE事件生效的时候,分别记录X,Y方向上的偏移。如果是X方向上的偏移,那么对应的就是SwipeMenuListView的特效操作;如果是Y方向上的偏移, Y方向向下,那么对应的就是下拉刷新操作,Y方向向上,那么对应的就是上拉操作。


Touch事件相关代码如下:

@Override  public boolean onTouchEvent(MotionEvent ev) {    if (mLastY == -1) {      mLastY = ev.getRawY();    }    switch (ev.getAction()) {    case MotionEvent.ACTION_DOWN:      mLastY = ev.getRawY();      int oldPos = mTouchPosition;      mDownX = ev.getX();      mDownY = ev.getY();      mTouchState = TOUCH_STATE_NONE;      mTouchPosition = pointToPosition((int) ev.getX(), (int) ev.getY());      if (mTouchPosition == oldPos && mTouchView != null && mTouchView.isOpen()) {        mTouchState = TOUCH_STATE_X;        mTouchView.onSwipe(ev);        return true;      }      View view = getChildAt(mTouchPosition - getFirstVisiblePosition());      if (mTouchView != null && mTouchView.isOpen()) {        mTouchView.smoothCloseMenu();        mTouchView = null;        return super.onTouchEvent(ev);      }      if (view instanceof SwipeMenuLayout) {        mTouchView = (SwipeMenuLayout) view;      }      if (mTouchView != null) {        mTouchView.onSwipe(ev);      }      break;    case MotionEvent.ACTION_MOVE:      final float deltaY = ev.getRawY() - mLastY;      mLastY = ev.getRawY();      // 非常感谢github上面的G友提出的宝贵建议和启发,这个地方要做一个判断。      // 在侧滑的过程当中不应该同时出现用户本不期望的下拉操作,      // 这样会给用户带来一种很不稳定的感受,是一种非常槽糕的用户体验。      // Modified on 9/16/2015      if (mTouchView == null || !mTouchView.isActive()) {        // 这个地方调换了if和else if的顺序,如果反过来会出现有时无法下拉刷新的bug        // Modified on 9/17/2015        if (getFirstVisiblePosition() == 0 && (mHeaderView.getVisiableHeight() > 0 || deltaY > 0)) {          // the first item is showing, header has shown or pull down.          updateHeaderHeight(deltaY / OFFSET_RADIO);          invokeOnScrolling();        } else if ((mFooterView.getBottomMargin() > 0 || deltaY < 0)) {          // last item, already pulled up or want to pull up.          updateFooterHeight(-deltaY / OFFSET_RADIO);        }      }      float dy = Math.abs((ev.getY() - mDownY));      float dx = Math.abs((ev.getX() - mDownX));      if (mTouchState == TOUCH_STATE_X) {        if (mTouchView != null) {          mTouchView.onSwipe(ev);        }        getSelector().setState(new int[] { 0 });        ev.setAction(MotionEvent.ACTION_CANCEL);        super.onTouchEvent(ev);        return true;      } else if (mTouchState == TOUCH_STATE_NONE) {        if (Math.abs(dy) > MAX_Y) {          mTouchState = TOUCH_STATE_Y;        } else if (dx > MAX_X) {          mTouchState = TOUCH_STATE_X;          if (mOnSwipeListener != null) {            mOnSwipeListener.onSwipeStart(mTouchPosition);          }        }      }      break;    // default:    // 非常感谢博友私信提出的修改意见,这个地方不应该写default,如果写成default的话,    // ACTION_POINTER_DOWN和ACTION_POINTER_UP事件也会执行下面的语句,    // 这样就会出现两个bug:    // 1.当下拉未松开时,屏幕上有其它点按下,下拉状态会变成松开;    // 2.当向左滑动列表的时候,屏幕上有其它点按下,再全部松开,滑出的列表会停在中间状态.    // Modified on 8/26/2015    case MotionEvent.ACTION_UP:      mLastY = -1; // reset      if (mEnablePullLoad && mFooterView.getBottomMargin() > PULL_LOAD_MORE_DELTA) {        startLoadMore();        resetFooterHeight();        // 再次感谢同一位博友的来信提出的新的bug        // 这个地方应该在加一个如下所示的resetHeaderHeight()异步操作,        // 如果不加这个操作的话,会导致下拉接着上拉后,刷新的Header卡住不动的状况,        // 由于resetHeaderHeight()和resetFooterHeight()牵涉同一变量mScroller,        // 因此这里通过Android封装的异步类AsyncTask实现footerHeight和headerHeight的恢复。        // resetFooterHeight(),resetHeaderHeight()其实是同步的,前者执行完毕才执行后者。        // Modified on 8/28/2015        new ResetHeaderHeightTask().execute();      } else if (getFirstVisiblePosition() == 0) {        // invoke refresh        if (mEnablePullRefresh && mHeaderView.getVisiableHeight() > mHeaderViewHeight) {          mPullRefreshing = true;          mHeaderView.setState(PullToRefreshListHeader.STATE_REFRESHING);          if (mListViewListener != null) {            mListViewListener.onRefresh();          }        }        resetHeaderHeight();      }      if (mTouchState == TOUCH_STATE_X) {        if (mTouchView != null) {          mTouchView.onSwipe(ev);          if (!mTouchView.isOpen()) {            mTouchPosition = -1;            mTouchView = null;          }        }        if (mOnSwipeListener != null) {          mOnSwipeListener.onSwipeEnd(mTouchPosition);        }        ev.setAction(MotionEvent.ACTION_CANCEL);        super.onTouchEvent(ev);        return true;      }      break;    }    return super.onTouchEvent(ev);  }  class ResetHeaderHeightTask extends AsyncTask<Void, Void, Void> {    protected Void doInBackground(Void... params) {      try {        Thread.sleep(400);      } catch (InterruptedException e) {        e.printStackTrace();      }      return null;    }    protected void onPostExecute(Void result) {      mPullRefreshing = false;      mHeaderView.setState(PullToRefreshListHeader.STATE_NORMAL);      resetHeaderHeight();    }  }

其实在整合这两套开源框架的时候遇到了不少的问题,归结起来其实是对Android的Touch事件把握的不充分导致的,真正把原理、基础搞透彻了,做起项目来才能得心应手啊。这里专门写了一篇关于Touch事件的博客:

http://blog.csdn.net/licaomengrice/article/details/48415431


更多相关文章

  1. Android下拉状态栏快捷开关的添加
  2. android 数据持久化——I/O操作
  3. 使用SpannableString设置部分文字大小、颜色、超链接、点击事件
  4. android 实例和分析
  5. 【Android(安卓)Developers Training】 7. 添加Action Buttons
  6. android事件分发(三)重要的函数requestDisallowInterceptTouchEven
  7. Android(安卓)文件操作
  8. android 在xml中指定按钮点击事件
  9. android设备管理器.md

随机推荐

  1. Android 自定义Html标签
  2. 在android 6.0以上无法获取READ_PHONE_ST
  3. android在使用RecyclerView布局里的andro
  4. Android Wear 开发-创建第一个卡片
  5. android 实现QQ好友列表
  6. 解决一个Android Studio gradle的小问题
  7. Android 官方示例:android-architecture
  8. Android之TextView 详细字典
  9. android多语言设置
  10. Android Studio如何生成APK文件