您的位置:首页 > 其它

[置顶] PullToRefreshListView总结

2016-03-02 20:16 337 查看
PullToRefreshListView工作原理:

       整体是个LinearLayout,包含一个Header,一个Footer,中间夹着一个ListView,其中Header和Footer的位置居于不可见范围内。

以竖向下拉为例,当接收到下拉手势时,如果ListView内容居于置顶位置,则LinearLayout向下滚动,显示出Header的内容,当Header内容展示完全后,如果用户松开,则进行刷新操作,当刷新完成后,LinearLayout向上滚动,回到初始位置。如果Header内容未展示完全,用户即松开,则LinearLayout直接回到初始位置。如果收到下拉手势时,ListView内容居于未置顶位置,LinearLayout会将手势交给ListView消费,ListView进行内容滑动。

问题一.LinearLayout如何加入header和footer

1.首先,PullToRefreshBase的init()方法中(构造函数中调用)

// Finally update the UI for the modes
updateUIForMode();


2. 看下updateUIForMode()方法

/**
* Updates the View State when the mode has been set. This does not do any
* checking that the mode is different to current state so always updates.
*/
protected void updateUIForMode() {
// We need to use the correct LayoutParam values, based on scroll
// direction
   final LinearLayout.LayoutParams lp = getLoadingLayoutLayoutParams();

// Remove Header, and then add Header Loading View again if needed
   if (this == mHeaderLayout.getParent()) {
removeView(mHeaderLayout);
}
   if (mMode.showHeaderLoadingLayout()) {
addViewInternal(mHeaderLayout, 0, lp);
}

// Remove Footer, and then add Footer Loading View again if needed
   if (this == mFooterLayout.getParent()) {
removeView(mFooterLayout);
}
   if (mMode.showFooterLoadingLayout()) {
addViewInternal(mFooterLayout, lp);
}

// Hide Loading Views
refreshLoadingViewsSize();

// If we're not using Mode.BOTH, set mCurrentMode to mMode, otherwise
// set it to pull down
   mCurrentMode = (mMode != Mode.BOTH) ? mMode : Mode.PULL_FROM_START;
}

       其中addViewInternal() 是LinearLayout将headerLayout和footerLayout添加的位置。

问题二.如何实现初始位置中不展示header和footer的?

看到问题一中,refreshLoadingViewSize()方法

/**
* Re-measure the Loading Views height, and adjust internal padding as
* necessary
*/
protected final void refreshLoadingViewsSize() {
   final int maximumPullScroll = (int) (getMaximumPullScroll() * 1.2f);

   int pLeft = getPaddingLeft();
   int pTop = getPaddingTop();
   int pRight = getPaddingRight();
   int pBottom = getPaddingBottom();

   switch (getPullToRefreshScrollDirection()) {
     case HORIZONTAL:
     if (mMode.showHeaderLoadingLayout()) {
         mHeaderLayout.setWidth(maximumPullScroll);
pLeft = -maximumPullScroll;
} else {
pLeft = 0;
}

      if (mMode.showFooterLoadingLayout()) {
         mFooterLayout.setWidth(maximumPullScroll);
pRight = -maximumPullScroll;
} else {
pRight = 0;
}
      break;

      case VERTICAL:
      if (mMode.showHeaderLoadingLayout()) {
         mHeaderLayout.setHeight(maximumPullScroll);
pTop = -maximumPullScroll;
} else {
pTop = 0;
}

      if (mMode.showFooterLoadingLayout()) {
         mFooterLayout.setHeight(maximumPullScroll);
pBottom = -maximumPullScroll;
} else {
pBottom = 0;
}
      break;
}

  if (DEBUG) {
Log.d(LOG_TAG, String.format(
"Setting Padding. L: %d, T: %d, R: %d, B: %d", pLeft, pTop,
pRight, pBottom));
}
setPadding(pLeft, pTop, pRight, pBottom);
}


问题三.PullToRefreshListView为何添加两个Header 两个Footer

PullToRefreshBase添加

PullToRefreshListView的ListView也添加了

但默认展示中只展示1个 两者互相切换

问题四.LinearLayout如何拦截手势操作

      onInterceptTouchEvent和onTouchEvent配合

      以竖向下拉为例

1.首先,onInterceptTouchEvent接收到ActionDown事件

    如果此时ListView内容居于置顶位置,则记录初始点击位置

//判断ListView内容是否居于置顶位置

private boolean isFirstItemVisible() {
   final Adapter adapter = mRefreshableView.getAdapter();

   if (null == adapter || adapter.isEmpty()) { //listView中无内容
      if (DEBUG) {
Log.d(LOG_TAG, "isFirstItemVisible. Empty View.");
}
      return true;
} else {
/**
* This check should really just be:
* mRefreshableView.getFirstVisiblePosition() == 0, but PtRListView
* internally use a HeaderView which messes the positions up. For
* now we'll just add one to account for it and rely on the inner
* condition which checks getTop().
*/
      if (mRefreshableView.getFirstVisiblePosition() <= 1) { // 显示ListView第一个元素
         final View firstVisibleChild = mRefreshableView.getChildAt(0);
         if (firstVisibleChild != null) {
            return firstVisibleChild.getTop() >= mRefreshableView.getTop(); //ListView第一个元素的顶部与ListView的顶部相符或者在ListView顶部的下面
}
}
}

   return false;
}


2.其次是接收到ActionMove事件,如果滑动距离大于最小滑动距离,且竖向滑动距离大于横向滑动距离,则认为处于滑动状态,将mIsBeingDragged设置true,onInterceptTouchEvent返回true。

3.这样交给LinearLayout的onTouchEvent处理,在ActionMove事件的处理中,调用pullEvent()方法,获取滑动距离、将LinearLayout滑动相应距离(显示header),同时header和footer根据滑动距离进行处理(动画)。如果滑动距离超过header高度,更改状态为松手刷新,同时传递给LoadingLayout进行处理。如果滑动距离不超过header高度,更改状态为下拉刷新,同时传递给LoadingLayout进行处理。

问题五.PullToRefreshListView控件是如何封装给用户直接使用的?如果不是封装的控件,自己如何实现PullToRefresh功能?

问题六.PullToRefreshListView如何实现xml属性设置和读取

问题七.PullToRefreshListView如何实现滚动、刷新等动画

问题八.PullToRefreshListView用到的设计模式
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: