转载请标明出处:
http://blog.csdn.net/xuehuayous/article/details/51158759;
本文出自:【Kevin.zhou的博客】
public class UltimateRecyclerView extends PullToRefreshBase<WrapRecyclerView> { public UltimateRecyclerView(Context context) { super(context); } public UltimateRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); } public UltimateRecyclerView(Context context, Mode mode) { super(context, mode); } public UltimateRecyclerView(Context context, Mode mode, AnimationStyle animStyle) { super(context, mode, animStyle); } @Override public Orientation getPullToRefreshScrollDirection() { return null; } @Override protected WrapRecyclerView createRefreshableView(Context context, AttributeSet attrs) { return null; } @Override protected boolean isReadyForPullEnd() { return false; } @Override protected boolean isReadyForPullStart() { return false; } }
@Override public final Orientation getPullToRefreshScrollDirection() { return Orientation.VERTICAL; }
@Override protected WrapRecyclerView createRefreshableView(Context context, AttributeSet attrs) { WrapRecyclerView recyclerView = new InternalWrapRecyclerView(context, attrs); recyclerView.setId(R.id.ultimate_recycler_view); return recyclerView; }这里为什么使用了一个InternalWrapRecyclerView,这个后面再讲。
@Override protected boolean isReadyForPullStart() { return isFirstItemVisible(); }
@Override protected boolean isReadyForPullEnd() { return isLastItemVisible(); }
private void init(Context context, AttributeSet attrs) { // Styleables from XML TypedArray ua = context.obtainStyledAttributes(attrs, R.styleable.UltimateRecyclerView); mURecyclerViewExtrasEnabled = ua.getBoolean(R.styleable.UltimateRecyclerView_ptrURecyclerViewExtrasEnabled, true); ua.recycle(); // Styleables from XML TypedArray pa = context.obtainStyledAttributes(attrs, com.handmark.pulltorefresh.library.R.styleable.PullToRefresh); if (mURecyclerViewExtrasEnabled) { final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL); final ViewGroup.LayoutParams hlp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); // Create Loading Views ready for use later mSvHeaderLoadingFrame = new FrameLayout(getContext()); mHeaderLoadingView = createLoadingLayout(getContext(), Mode.PULL_FROM_START, pa); mHeaderLoadingView.setVisibility(View.GONE); mSvHeaderLoadingFrame.addView(mHeaderLoadingView, lp); mSvHeaderLoadingFrame.setLayoutParams(hlp); mRefreshableView.addHeaderView(mSvHeaderLoadingFrame); mSvFooterLoadingFrame = new FrameLayout(getContext()); mFooterLoadingView = createLoadingLayout(getContext(), Mode.PULL_FROM_END, pa); mFooterLoadingView.setVisibility(View.GONE); mSvFooterLoadingFrame.addView(mFooterLoadingView, lp); mSvFooterLoadingFrame.setLayoutParams(hlp); mSvSecondFooterLoadingFrame = new FrameLayout(getContext()); mSvSecondFooterLoadingFrame.setLayoutParams(hlp); pa.recycle(); } }
protected class InternalWrapRecyclerView extends WrapRecyclerView { private boolean mAddedSvFooter = false; public InternalWrapRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); } @Override public void setAdapter(Adapter adapter) { // Add the Footer View at the last possible moment if (null != mSvFooterLoadingFrame && !mAddedSvFooter) { addFooterView(mSvFooterLoadingFrame); mAddedSvFooter = true; } super.setAdapter(adapter); } }
@Override protected void onRefreshing(final boolean doScroll) { WrapAdapter adapter = mRefreshableView.getAdapter(); if (!mURecyclerViewExtrasEnabled || !getShowViewWhileRefreshing() || null == adapter || adapter.getItemCount() == 0) { super.onRefreshing(doScroll); return; } super.onRefreshing(false); final LoadingLayoutBase origLoadingView, recyclerViewLoadingView, oppositeRecyclerViewLoadingView; final int scrollToPosition, scrollToY; switch (getCurrentMode()) { case MANUAL_REFRESH_ONLY: case PULL_FROM_END: origLoadingView = getFooterLayout(); recyclerViewLoadingView = mFooterLoadingView; oppositeRecyclerViewLoadingView = mHeaderLoadingView; scrollToPosition = mRefreshableView.getBottom(); scrollToY = getScrollY() - getFooterSize(); break; case PULL_FROM_START: default: origLoadingView = getHeaderLayout(); recyclerViewLoadingView = mHeaderLoadingView; oppositeRecyclerViewLoadingView = mFooterLoadingView; scrollToPosition = mRefreshableView.getTop(); scrollToY = getScrollY() + getHeaderSize(); break; } // 隐藏原来的加载View origLoadingView.reset(); origLoadingView.hideAllViews(); // 刷新时隐藏尾部,加载时隐藏头部 oppositeRecyclerViewLoadingView.setVisibility(View.GONE); // 设置RecyclerView内的加载View显示并设置它为刷新状态 recyclerViewLoadingView.setVisibility(View.VISIBLE); recyclerViewLoadingView.refreshing(); if (doScroll) { // We need to disable the automatic visibility changes for now disableLoadingLayoutVisibilityChanges(); // 刷新布局由过度滑动状态恢复 setHeaderScroll(scrollToY); // 让添加到RecyclerView的刷新头部或者加载尾部显示出来 mRefreshableView.smoothScrollToPosition(scrollToPosition); // 把整体滚回初始位置 smoothScrollTo(0); } }
@Override protected void onReset() { if (!mURecyclerViewExtrasEnabled) { super.onReset(); return; } final LoadingLayoutBase originalLoadingLayout, recyclerViewLoadingLayout; final int scrollToHeight, selection; final boolean scrollSvToEdge; WrapAdapter adapter = mRefreshableView.getAdapter(); switch (getCurrentMode()) { case MANUAL_REFRESH_ONLY: case PULL_FROM_END: originalLoadingLayout = getFooterLayout(); recyclerViewLoadingLayout = mFooterLoadingView; selection = adapter.getItemCount() - 1; scrollToHeight = getFooterSize(); scrollSvToEdge = Math.abs(getLastVisiblePosition() - selection) <= 1; break; case PULL_FROM_START: default: originalLoadingLayout = getHeaderLayout(); recyclerViewLoadingLayout = mHeaderLoadingView; scrollToHeight = -getHeaderSize(); selection = 0; scrollSvToEdge = Math.abs(getFirstVisiblePosition() - selection) <= 1; break; } // 如果添加到RecyclerView的加载布局在显示 if (recyclerViewLoadingLayout.getVisibility() == View.VISIBLE) { // 显示原来的加载布局 originalLoadingLayout.showInvisibleViews(); // 隐藏添加到RecyclerView的加载布局 recyclerViewLoadingLayout.setVisibility(View.GONE); // 滚动隐藏头部或者尾部 if (scrollSvToEdge && getState() != State.MANUAL_REFRESHING) { mRefreshableView.scrollToPosition(selection); setHeaderScroll(scrollToHeight); } } super.onReset(); }
public final void setOnLastItemVisibleListener(OnLastItemVisibleListener listener) { mOnLastItemVisibleListener = listener; }
public static interface OnLastItemVisibleListener { public void onLastItemVisible(); }
/** * 判断最后一个条目是否能够可见 * * @return boolean: * @version 1.0 * @date 2016-4-12 14:51:04 * @Author zhou.wenkai */ private boolean isLastItemVisible() { final RecyclerView.Adapter<?> adapter = getRefreshableView().getAdapter(); // 如果未设置Adapter,都没有添加自然不可见 if(null == adapter) { return false; } else { // 最后一个条目View是否展示 int lastVisiblePosition = getLastVisiblePosition(); // 最后一个显示出来了 if(lastVisiblePosition == mRefreshableView.getAdapter().getItemCount() - 2) { // 说明最后一个刚刚显示出来 // 这里不希望和PullToRefreshListView中一样只要最后一个显示,每动一下就促发一次回调 if(lastVisiblePosition == mTmplastVisiblePosition + 1) { mTmplastVisiblePosition = lastVisiblePosition; return true; } } mTmplastVisiblePosition = lastVisiblePosition; } return false; }
private int getLastVisiblePosition() { View lastVisibleChild = mRefreshableView.getChildAt(mRefreshableView .getChildCount() - 1); return lastVisibleChild != null ? mRefreshableView .getChildAdapterPosition(lastVisibleChild) : -1; }
@Override public void onScrolled(int dx, int dy) { super.onScrolled(dx, dy); boolean lastItemVisible = isLastItemVisible(); if(lastItemVisible) { mOnLastItemVisibleListener.onLastItemVisible(); } }
@Override public void setHeaderLayout(LoadingLayoutBase headerLayout) { super.setHeaderLayout(headerLayout); try { Constructor c = headerLayout.getClass().getDeclaredConstructor(new Class[]{Context.class}); LoadingLayoutBase mHeaderLayout = (LoadingLayoutBase)c.newInstance(new Object[]{getContext()}); if(null != mHeaderLayout) { mSvHeaderLoadingFrame.removeAllViews(); final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL); mHeaderLoadingView = mHeaderLayout; mHeaderLoadingView.setVisibility(View.GONE); mSvHeaderLoadingFrame.addView(mHeaderLoadingView, lp); mRefreshableView.getAdapter().notifyDataSetChanged(); } } catch (Exception e) { e.printStackTrace(); } }
@Override public void setFooterLayout(LoadingLayoutBase footerLayout) { super.setFooterLayout(footerLayout); try { Constructor c = footerLayout.getClass().getDeclaredConstructor(new Class[]{Context.class}); LoadingLayoutBase mFooterLayout = (LoadingLayoutBase)c.newInstance(new Object[]{getContext()}); if(null != mFooterLayout) { mSvFooterLoadingFrame.removeAllViews(); final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL); mFooterLoadingView = mFooterLayout; mFooterLoadingView.setVisibility(View.GONE); mSvFooterLoadingFrame.addView(mFooterLoadingView, lp); mRefreshableView.getAdapter().notifyDataSetChanged(); } } catch (Exception e) { e.printStackTrace(); } }
@Override public void setAdapter(Adapter adapter) { // Add the Footer View at the last possible moment if (null != mSvFooterLoadingFrame && !mAddedSvFooter) { addFooterView(mSvSecondFooterLoadingFrame); addFooterView(mSvFooterLoadingFrame); mAddedSvFooter = true; } super.setAdapter(adapter); }
@Override public void setSecondFooterLayout(View secondFooterLayout) { final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL); mSvSecondFooterLoadingFrame.addView(secondFooterLayout, lp); }
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:ptr="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <com.kevin.ultimaterecyclerview.UltimateRecyclerView android:id="@+id/main_act_urv" android:layout_width="match_parent" android:layout_height="match_parent" ptr:ptrMode="pullFromStart"> </com.kevin.ultimaterecyclerview.UltimateRecyclerView> </RelativeLayout>
mUltimateRecyclerView = (UltimateRecyclerView) this.findViewById(R.id.main_act_urv); // 设置头部刷新样式为自定义 mUltimateRecyclerView.setHeaderLayout(new TmallHeaderLayout(this));
WrapRecyclerView mWrapRecyclerView = mUltimateRecyclerView.getRefreshableView();
LayoutInflater inflater = LayoutInflater.from(this); FrameLayout layout = (FrameLayout) inflater.inflate(R.layout.recycler_header, null); mAdLoopView = (AdLoopView) layout.findViewById(R.id.main_act_alv); mWrapRecyclerView.addHeaderView(layout);
// 设置刷新监听 mUltimateRecyclerView.setOnRefreshListener(new PullToRefreshBase.OnRefreshListener<WrapRecyclerView>() { @Override public void onRefresh(PullToRefreshBase<WrapRecyclerView> refreshView) { new GetDataTask(true).execute(); } });
// 设置最后一个条目可见监听 mUltimateRecyclerView.setOnLastItemVisibleListener(new PullToRefreshBase.OnLastItemVisibleListener() { @Override public void onLastItemVisible() { boolean hasMoreData = secondFooterLayout.isHasMoreData(); Log.i("", "是否还有更多数据 " + hasMoreData); if(hasMoreData) { new GetDataTask(false).execute(); } } });
如果您的项目使用 Gradle 构建, 只需要在您的build.gradle
文件添加下面一行到 dependencies
:
compile 'com.kevin:ultimaterecyclerview:1.0.1'