一个符合MVP设计要求,且具备上拉刷新功能的RecyclerView
先看一下UML简图:
接下来是代码:
首先来看一下Presenter:
public class Presenter1 { ViewLayer1 mViewLayer; Recycler1Module mRecyclerModule = new Recycler1Module(); public Presenter1(ViewLayer1 viewLayer) { this.mViewLayer = viewLayer; /** * 设置加载更多的监听回调 */ mViewLayer.setOnNeedLoadListener(new OnNeedLoadListener() { @SuppressWarnings("static-access") @Override public void loadMore(int from, int length) { mRecyclerModule.loadMore(from, length, new OnDataLoadedListener() { @Override public void onDataLoaded( final List<AppCardViewBean> cardViewBeanList) { // 加载更多成功 mViewLayer.showMoreContent(cardViewBeanList); mViewLayer .setLoadStatusNrefreshFooter(LoadStatus.DRAG_UP_TO_LAOD_MORE); } @Override public void onDataLoadFailed(Throwable e) { // 加载更多失败 Toast.makeText( mViewLayer.getInnerView().getContext(), "未能读取到数据", 0).show(); // mViewLayer.showError(e); mViewLayer.showLoadMoreFailure(); mViewLayer .setLoadStatusNrefreshFooter(LoadStatus.DRAG_UP_TO_LAOD_MORE); } }); } }); } /** * 方法名要改 */ public void onActivityCreate() { /** * 初始化module */ // mModule = new Module1(); loadData(0, Constance.ITEM_IN_A_PAGE);// 这个时候加载第一页 } void onActivityDestroyed() { // TODO 目前什么都不做 } /** * 在界面初始化的时候调用这个方法 这个方法会根据情况让显示层显示loading,content或者error * * @param pageNum * 暂时还没用到 */ @SuppressWarnings("static-access") void loadData(int from, int length) { mViewLayer.showLoading(); // load data from module and let view show them mRecyclerModule.loadMore(from, length, new OnDataLoadedListener() { @Override public void onDataLoaded( final List<AppCardViewBean> cardViewBeanList) { // 第一次加载成功 // 点击事件 mViewLayer.showFirstPageContent(cardViewBeanList, new RecyclerViewOnClickListener() { @Override public void onItemClicked(View view, int position) { Intent intent = new Intent( UiUtils.getContext(), AppDetailActivity.class); intent.putExtra("app_name", "position:"+position); UiUtils.startActivity(intent); } }); } @Override public void onDataLoadFailed(Throwable e) { // 第一次加载失败 Toast.makeText(mViewLayer.getInnerView().getContext(), "未能读取到数据", 0).show(); mViewLayer.showError(e); } }); } public interface OnDataLoadedListener { void onDataLoaded(List<AppCardViewBean> cardViewBeanList); void onDataLoadFailed(Throwable e); } }
接下来看ViewLayer:
public class ViewLayer1 { private PullUpRecyclerController mRecyclerController; private View mView; private TextView mErrorTextView; private ProgressBar mProgressBar; Context context; SwipeRefreshLayout mSwipRefreshLayout; public ViewLayer1(Context context) { this.context = context; LayoutInflater inflater = LayoutInflater.from(context); mView = inflater.inflate(R.layout.frag1layout, null); RecyclerView recyclerView = (RecyclerView) mView .findViewById(R.id.recyclerView); mRecyclerController = new PullUpRecyclerController(context, recyclerView); mErrorTextView = (TextView) mView.findViewById(R.id.errorView); mProgressBar = (ProgressBar) mView.findViewById(R.id.loadingView); mSwipRefreshLayout = (SwipeRefreshLayout) mView .findViewById(R.id.contentView); /** * 目前没有下拉的逻辑 */ mSwipRefreshLayout.setOnRefreshListener(new OnRefreshListener() { @Override public void onRefresh() { new Handler().postDelayed(new Runnable() { @Override public void run() { mSwipRefreshLayout.setRefreshing(false); } }, 1200); } }); } /** * 第一次showContent之前一定要先调用这个方法 * * @param mOnNeedLoadListener */ public void setOnNeedLoadListener(OnNeedLoadListener mOnNeedLoadListener) { mRecyclerController.setOnNeedLoadListener(mOnNeedLoadListener); } public View getInnerView() { // return mListView; // return mSwipRefreshLayout; return mView; } public void showLoading() { mErrorTextView.setVisibility(View.INVISIBLE); mSwipRefreshLayout.setVisibility(View.INVISIBLE); mProgressBar.setVisibility(View.VISIBLE); } /** * 在显示第一页的时候调用,之后就没再调用了 * * @param beanList * @param onclickListener */ public void showFirstPageContent(List<AppCardViewBean> beanList, RecyclerViewOnClickListener onclickListener) { mErrorTextView.setVisibility(View.INVISIBLE); mProgressBar.setVisibility(View.INVISIBLE); mSwipRefreshLayout.setVisibility(View.VISIBLE); mRecyclerController.showFirstpageItems(beanList); mRecyclerController.setOnItemClickListener(onclickListener); } public void showError(Throwable e) { mSwipRefreshLayout.setVisibility(View.INVISIBLE); mProgressBar.setVisibility(View.INVISIBLE); mErrorTextView.setVisibility(View.VISIBLE); } public void showMoreContent(List<AppCardViewBean> cardViewBeanList) { mRecyclerController.showMoreItems(cardViewBeanList); } public void setLoadStatusNrefreshFooter(LoadStatus clickLoadMore) { mRecyclerController.setLoadStatusNrefreshFooter(clickLoadMore); } /** * 加载更多未获取到数据时调用此方法,目前留空 */ public void showLoadMoreFailure() { } }
接下来是PullUpRecyclerController:
public class PullUpRecyclerController { private RecyclerView mRecyclerView; private RecyclerAdapter1 mAdapter; private int mLastVisibleItemPosition = 0; private LinearLayoutManager mLayoutManager; private Context mContext; private OnNeedLoadListener mOnNeedLoadListener; public PullUpRecyclerController(Context context, RecyclerView recyclerView) { onCreate(context, recyclerView); } protected void onCreate(Context context, RecyclerView recyclerView) { mContext = context; mRecyclerView = recyclerView; mLayoutManager = new LinearLayoutManager(context); mRecyclerView.setLayoutManager(mLayoutManager); mRecyclerView.setItemAnimator(new DefaultItemAnimator()); } public View getRecyclerView() { return mRecyclerView; } /** * 构造方法已经调用此方法 当想要更换listener时再调用此方法 * * @param listener */ public void setOnNeedLoadListener(OnNeedLoadListener listener) { this.mOnNeedLoadListener = listener; } public interface OnNeedLoadListener { public void loadMore(int from, int length); } /** * 第一次显示recyclerView的时候调用的方法。 * * @param list */ @SuppressWarnings("deprecation") public void showFirstpageItems(List<AppCardViewBean> list) { mAdapter = new RecyclerAdapter1(mContext, list); mRecyclerView.setAdapter(mAdapter); mRecyclerView.setOnScrollListener(new OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); if (newState == RecyclerView.SCROLL_STATE_IDLE && mLastVisibleItemPosition + 1 == mAdapter .getItemCount()) { if (mOnNeedLoadListener != null) { /** * 在调用回调接口前,要先确定是否已经在回调了 没有在回调的话,还要更新footer */ if (Recycler1Module.isLoadingMore) { return; } Recycler1Module.isLoadingMore = true; setLoadStatusNrefreshFooter(LoadStatus.LOADING_MORE); /** * 调用回调接口 */ mOnNeedLoadListener.loadMore(mAdapter.getItemCount(), Constance.ITEM_IN_A_PAGE); } } } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); mLastVisibleItemPosition = mLayoutManager .findLastVisibleItemPosition(); } }); } /** * 显示更多条目 应该先调用showFirstpageItems方法 * * @param list */ public void showMoreItems(List<AppCardViewBean> list) { mAdapter.addAllNRefresh(list); } /** * 调用adapter的同名方法 并暴露给ViewLayer * * @param clickLoadMore */ public void setLoadStatusNrefreshFooter(LoadStatus clickLoadMore) { mAdapter.setLoadStatusNrefreshFooter(clickLoadMore); } /** * 要再showFirstPageItems之后调用此方法 * @param listener */ public void setOnItemClickListener(RecyclerViewOnClickListener listener){ mAdapter.setOnItemClickListener(listener); } }
接下来是RecyclerAdapter:
public class RecyclerAdapter1 extends RecyclerView.Adapter<ViewHolder> { private static final int VIEW_TYPE_FOOTER = 0; private static final int VIEW_TYPE_ITEM = 1; private List<AppCardViewBean> mList; private LayoutInflater mInflater; private Context mContext; private LoadStatus mLoadStatus = LoadStatus.DRAG_UP_TO_LAOD_MORE; private RecyclerViewOnClickListener mOnItemClickListener; private Recycler1Module mForData = new Recycler1Module(); public RecyclerAdapter1(Context context, List<AppCardViewBean> list) { this.mContext = context; mInflater = LayoutInflater.from(context); this.mList = list; } @Override public int getItemCount() { return mList.size() + 1; } @Override public int getItemViewType(int position) { if (position + 1 == getItemCount()) {// 最后一条数据 return VIEW_TYPE_FOOTER; } else { return VIEW_TYPE_ITEM; } } @Override public void onBindViewHolder(ViewHolder holder, int position) { switch (getItemViewType(position)) { case VIEW_TYPE_FOOTER: onBindFooterViewHolder(holder, position, mLoadStatus); break; case VIEW_TYPE_ITEM: onBindItemViewHolder(holder, position); break; default: break; } } private void onBindFooterViewHolder(ViewHolder holder, int position, LoadStatus mLoadStatus2) { FooterViewHolder viewHolder = (FooterViewHolder) holder; switch (mLoadStatus2) { case DRAG_UP_TO_LAOD_MORE: viewHolder.mLoadingLayout.setVisibility(View.GONE); viewHolder.mClickLoad.setVisibility(View.VISIBLE); break; case LOADING_MORE: viewHolder.mLoadingLayout.setVisibility(View.VISIBLE); viewHolder.mClickLoad.setVisibility(View.GONE); break; case LOAD_FAILED: break; case LOAD_END: break; } } private void onBindItemViewHolder(ViewHolder holder, int position) { ItemViewHolder viewHolder = (ItemViewHolder) holder; viewHolder.cardView.setAppName(mList.get(position).getAppName()); viewHolder.cardView.setSizeText(mList.get(position).getAppSize()); viewHolder.cardView.setBriefDesc(mList.get(position).getBriefDesc()); } // ===================onCreateHolder below================== @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == VIEW_TYPE_FOOTER) { return onCreateFooterViewHolder(parent, viewType); } else if (viewType == VIEW_TYPE_ITEM) { return onCreateItemViewHolder(parent, viewType); } else { return null; } } private ViewHolder onCreateItemViewHolder(ViewGroup parent, int viewType) { AppMainCardView view = new AppMainCardView(mContext); return new ItemViewHolder(view, mOnItemClickListener); } private ViewHolder onCreateFooterViewHolder(ViewGroup parent, int viewType) { View view = mInflater.inflate(R.layout.item_footer, null); return new FooterViewHolder(view); } /** * 普通item的条目的holder * * @author administrator1 * */ class ItemViewHolder extends RecyclerView.ViewHolder { private AppMainCardView cardView; private RecyclerViewOnClickListener mListener; public ItemViewHolder(View view, RecyclerViewOnClickListener listener) { super(view); cardView = (AppMainCardView) view; this.mListener = listener; view.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (mListener != null) { mListener.onItemClicked(v, getPosition());// 应该用getlayoutposition? } } }); } } class FooterViewHolder extends RecyclerView.ViewHolder { public LinearLayout mLoadingLayout; public TextView mClickLoad; public FooterViewHolder(View itemView) { super(itemView); mLoadingLayout = (LinearLayout) itemView.findViewById(R.id.loading); mClickLoad = (TextView) itemView.findViewById(R.id.click_load_txt); mClickLoad.setOnClickListener(new View.OnClickListener() {// 添加点击加载更多监听 @Override public void onClick(View v) { } }); } } // ===========================method about data========= /** * 唯一的实现刷新效果的,就这两行语句实现刷新效果 * * @param list */ public void addAllNRefresh(List<AppCardViewBean> list) { this.mList.addAll(list); notifyDataSetChanged(); } public void reSetData(List<AppCardViewBean> list) { this.mList = list; notifyDataSetChanged(); } /** * 设置Adapter的状态并且刷新footer 被controller调用 * * @param status */ public void setLoadStatusNrefreshFooter(LoadStatus status) { this.mLoadStatus = status; this.notifyItemChanged(getItemCount() - 1); } public enum LoadStatus { DRAG_UP_TO_LAOD_MORE, // 点击加载更多 LOADING_MORE, // 正在加载更多 LOAD_FAILED, LOAD_END } /** * 设置点击事件 * @param listener */ public void setOnItemClickListener(@NonNull RecyclerViewOnClickListener listener) { mOnItemClickListener = listener; } }
module的代码就不贴了
最后是在fragment中的使用:
public class Fragment1 extends BaseFragment{ Presenter1 mPresenter; ViewLayer1 mViewLayer; @Override @Nullable public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { mViewLayer = new ViewLayer1(this.getContext()); mPresenter = new Presenter1(mViewLayer); mPresenter.onActivityCreate(); return mViewLayer.getInnerView(); } }