zoukankan      html  css  js  c++  java
  • 一个符合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();
        }
    }
  • 相关阅读:
    TypeScript 引入第三方包却报错:"无法找到模块"
    TS与hook useState
    原生js《发布订阅》功能
    react EUI 《消息通知》组件封装
    react 父级调用子级方法
    本人前端的面试笔记
    uniCloud云函数公共模块导入错误
    前端常见安全性问题
    2020 Qcon 深圳场参会感想
    嵌入式TF卡全备份与恢复嵌入式TF卡全备份与恢复
  • 原文地址:https://www.cnblogs.com/BlogCommunicator/p/7383389.html
Copyright © 2011-2022 走看看