前言
在很早以前在本人的博客 https://www.cnblogs.com/guanxinjing/p/10299889.html 提供了用RecyclerView实现上拉加载数据的思维,但是用这个方式实现后,每一个上拉加载页面几乎都需要重写大量重复代码。所以进行了重新的封装,以方便使用并且减少重复代码量。如果刚点击这个博客建议看看之前的博客,之前的博客实现思路比较,清晰讲解部分也比较多。
封装后的RecyclerView
使用时请注意,这里以内部类的形式封装了适配器,请使用这里封装的适配器配合一起使用。
import android.content.Context; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; import android.widget.TextView; import androidx.annotation.ColorInt; import androidx.annotation.IntDef; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.StringRes; import androidx.recyclerview.widget.RecyclerView; import java.lang.annotation.Retention; import java.lang.annotation.Target; import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.RetentionPolicy.SOURCE; public class UpLoadingRecyclerView extends RecyclerView { private boolean isScroll; private float downY; private int mHeightPixels; private OnUpScrollListener mOnUpScrollListener; private OnUpPullLoadListener mOnUpPullLoadListener; public UpLoadingRecyclerView(@NonNull Context context) { super(context); DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); mHeightPixels = displayMetrics.heightPixels; } public UpLoadingRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); mHeightPixels = displayMetrics.heightPixels; } public UpLoadingRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); mHeightPixels = displayMetrics.heightPixels; } @Override public boolean dispatchTouchEvent(MotionEvent ev) { return super.dispatchTouchEvent(ev); } /** * 重写拦截的目的是只拦截移动事件,不拦截其他触摸事件 * * @param e * @return */ @Override public boolean onInterceptTouchEvent(MotionEvent e) { super.onInterceptTouchEvent(e);//一定要super.onInterceptTouchEvent(e);不要让RecyclerView的其他事件分发受到影响,否则会出现不滚动的问题 switch (e.getAction()) { case MotionEvent.ACTION_DOWN: isScroll = false;//按下不拦截 downY = e.getY(); break; case MotionEvent.ACTION_MOVE: if (Math.abs(downY - e.getY()) >= ViewConfiguration.get( getContext()).getScaledTouchSlop()) {//判断是否产生了最小滑动 isScroll = true;//移动了拦截触摸事件 } else { isScroll = false; } break; case MotionEvent.ACTION_UP: isScroll = false;//松开不拦截 break; } return isScroll; } @Override public boolean onFilterTouchEventForSecurity(MotionEvent event) { return super.onFilterTouchEventForSecurity(event); } @Override public boolean onTouchEvent(MotionEvent e) { switch (e.getAction()) { case MotionEvent.ACTION_DOWN: break; case MotionEvent.ACTION_MOVE: break; case MotionEvent.ACTION_UP: if (downY - e.getY() > mHeightPixels / 5) {//判断是不是从下往上滑动了屏幕的5分之一 if (mOnUpScrollListener != null) { mOnUpScrollListener.onScroll(); } if (getAdapter() != null && mOnUpPullLoadListener != null && getAdapter() instanceof Adapter) { Adapter adapter = (Adapter) getAdapter(); if (adapter.isFooterPullUpLoading() && adapter.isFooterItemPosition()) { mOnUpPullLoadListener.OnUpPullLoad(); } } } break; } return super.onTouchEvent(e); } public void setOnUpScrollListener(OnUpScrollListener listener) { this.mOnUpScrollListener = listener; } public void setOnUpPullLoadListener(OnUpPullLoadListener onUpPullLoadListener) { this.mOnUpPullLoadListener = onUpPullLoadListener; } public interface OnUpScrollListener { void onScroll(); } public interface OnUpPullLoadListener { void OnUpPullLoad(); } public static abstract class Adapter<VH extends ViewHolder> extends RecyclerView.Adapter { private static final int FOOTER_VIEW = -101; private int currentFooterStatus = FooterStatus.FOOTER_NO_MORE_DATA; //当前页角item状态 private int scrollPosition; //滚动位置 public abstract ViewHolder onCreateItemViewHolder(@NonNull ViewGroup parent, int viewType); public abstract ViewHolder onCreateFooterViewHolder(@NonNull ViewGroup parent, int viewType); public abstract void onBindItemViewHolder(@NonNull ViewHolder holder, int position); public abstract void onBindFooterViewHolder(@NonNull ViewHolder holder, @FooterStatus int currentFooterStatus); public abstract int getItemViewCount(); @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { if (viewType != FOOTER_VIEW) { return onCreateItemViewHolder(parent, viewType); } return onCreateFooterViewHolder(parent, viewType); } @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { scrollPosition = position; if (getItemViewType(position) != FOOTER_VIEW) { onBindItemViewHolder(holder, position); return; } onBindFooterViewHolder(holder, currentFooterStatus); } /** * 判断是否到了页尾的位置上 * * @return */ public boolean isFooterItemPosition() { return scrollPosition >= getItemCount() - 5; } @Override public int getItemViewType(int position) { if (getItemCount() != 0 && position == getItemCount() - 1) { return FOOTER_VIEW; } return super.getItemViewType(position); } @Override public int getItemCount() { return getItemViewCount() == 0 ? 0 : getItemViewCount() + 1; } /** * 修改页脚状态为加载中 */ public void setFooterLoading() { currentFooterStatus = FooterStatus.FOOTER_LOADING; notifyDataSetChanged(); } /** * 修改页脚状态为网络异常 */ public void setFooterNetWorkError() { currentFooterStatus = FooterStatus.FOOTER_ERROR; notifyDataSetChanged(); } /** * 修改页脚状态为没有更多数据 */ public void setFooterNoMoreData() { currentFooterStatus = FooterStatus.FOOTER_NO_MORE_DATA; notifyDataSetChanged(); } /** * 修改页脚状态为上拉加载数据 */ public void setFooterPullUpLoading() { currentFooterStatus = FooterStatus.FOOTER_PULL_UP_LOADING; notifyDataSetChanged(); } public boolean isFooterLoading() { return currentFooterStatus == FooterStatus.FOOTER_LOADING; } public boolean isFooterNetWorkError() { return currentFooterStatus == FooterStatus.FOOTER_ERROR; } public boolean isFooterNoMoreData() { return currentFooterStatus == FooterStatus.FOOTER_NO_MORE_DATA; } public boolean isFooterPullUpLoading() { return currentFooterStatus == FooterStatus.FOOTER_PULL_UP_LOADING; } /** * 创建使用简单页尾 * * @param parent * @param viewType * @param textSize * @param textColor * @return */ public SimpleFooterViewHolder createSimpleFooterView(@NonNull ViewGroup parent, int viewType, float textSize, @ColorInt int textColor) { if (viewType == Adapter.FOOTER_VIEW) { TextView textView = new TextView(parent.getContext()); if(textSize != 0){ textView.setTextSize(textSize); } if (textColor != 0){ textView.setTextColor(textColor); } textView.setGravity(Gravity.CENTER); textView.post(new Runnable() { @Override public void run() { ViewGroup.LayoutParams layoutParams = textView.getLayoutParams(); layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT; textView.setLayoutParams(layoutParams); } }); return new SimpleFooterViewHolder(textView); } return null; } /** * 绑定简单页尾的ViewHolder * * @param holder * @param pullUpLoadingText 提示 上拉加载数据 * @param loadingText 提示 数据加载中 * @param errorText 提示 网络异常 * @param notMoreDataText 提示 没有更多数据了 */ public void bindSimpleFooterViewHolder(@NonNull ViewHolder holder, @StringRes int pullUpLoadingText, @StringRes int loadingText, @StringRes int errorText, @StringRes int notMoreDataText) { if (holder instanceof SimpleFooterViewHolder) { switch (currentFooterStatus) { case FooterStatus.FOOTER_PULL_UP_LOADING: ((SimpleFooterViewHolder) holder).footerTextView.setText(pullUpLoadingText); break; case FooterStatus.FOOTER_LOADING: ((SimpleFooterViewHolder) holder).footerTextView.setText(loadingText); break; case FooterStatus.FOOTER_ERROR: ((SimpleFooterViewHolder) holder).footerTextView.setText(errorText); break; case FooterStatus.FOOTER_NO_MORE_DATA: ((SimpleFooterViewHolder) holder).footerTextView.setText(notMoreDataText); break; default: break; } } } /** * 绑定简单页尾的ViewHolder * * @param holder * @param pullUpLoadingText 提示 上拉加载数据 * @param loadingText 提示 数据加载中 * @param errorText 提示 网络异常 * @param notMoreDataText 提示 没有更多数据了 */ public void bindSimpleFooterViewHolder(@NonNull ViewHolder holder, String pullUpLoadingText, String loadingText, String errorText, String notMoreDataText) { if (holder instanceof SimpleFooterViewHolder) { switch (currentFooterStatus) { case FooterStatus.FOOTER_PULL_UP_LOADING: ((SimpleFooterViewHolder) holder).footerTextView.setText(pullUpLoadingText); break; case FooterStatus.FOOTER_LOADING: ((SimpleFooterViewHolder) holder).footerTextView.setText(loadingText); break; case FooterStatus.FOOTER_ERROR: ((SimpleFooterViewHolder) holder).footerTextView.setText(errorText); break; case FooterStatus.FOOTER_NO_MORE_DATA: ((SimpleFooterViewHolder) holder).footerTextView.setText(notMoreDataText); break; default: break; } } } public static class SimpleFooterViewHolder extends ViewHolder { TextView footerTextView; public SimpleFooterViewHolder(@NonNull View itemView) { super(itemView); footerTextView = (TextView) itemView; } } } @Retention(SOURCE) @Target({PARAMETER}) @IntDef(value = {FooterStatus.FOOTER_PULL_UP_LOADING, FooterStatus.FOOTER_LOADING, FooterStatus.FOOTER_ERROR, FooterStatus.FOOTER_NO_MORE_DATA}) public @interface FooterStatus { int FOOTER_PULL_UP_LOADING = 0; //提示上拉加载更多 int FOOTER_LOADING = 1; //加载中 int FOOTER_ERROR = 2; //网络异常 int FOOTER_NO_MORE_DATA = 3; //没有更多内容 } }
使用例子
Adpater
class HomeVideoAdapter extends UpLoadingRecyclerView.Adapter<RecyclerView.ViewHolder> { private List<HomeVideoBean> mList = new ArrayList<>(); private int mSelected = 0; private SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss", Locale.getDefault()); private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()); private OnClickListener mListener; public void refreshData(List<HomeVideoBean> list) { mList.clear(); if (list != null) { mList.addAll(list); } notifyDataSetChanged(); } public void addData(List<HomeVideoBean> list) { if (list != null) { mList.addAll(list); } notifyDataSetChanged(); } @Override public RecyclerView.ViewHolder onCreateItemViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.ad_item_home_video, parent, false); HomeVideoViewHolder viewHolder = new HomeVideoViewHolder(view); view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int position = viewHolder.getAdapterPosition(); if (position == RecyclerView.NO_POSITION) { return; } mSelected = position; notifyDataSetChanged(); if (mListener != null) { mListener.onClickItem(mList.get(position)); } } }); return viewHolder; } @Override public RecyclerView.ViewHolder onCreateFooterViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.ad_ad_layout_pull_up_refresh, parent, false); view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mListener != null) { mListener.onClickFooter(); } } }); return new FooterViewHolder(view); } @Override public void onBindItemViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { HomeVideoViewHolder viewHolder = (HomeVideoViewHolder) holder; HomeVideoBean bean = mList.get(position); if (mSelected == position) { viewHolder.icon.setImageResource(R.drawable.ad_ic_video_selected); } else { viewHolder.icon.setImageResource(R.drawable.ad_ic_video_no_selected); } viewHolder.content.setText(bean.getContent()); long ts = 0; try { ts = dateFormat.parse(bean.getCreateTime()).getTime(); } catch (ParseException e) { e.printStackTrace(); } viewHolder.time.setText(timeFormat.format(ts)); viewHolder.videoImage.setImageURI(bean.getFileUrl() + "?vframe/jpg/offset/1"); } @Override public void onBindFooterViewHolder(@NonNull RecyclerView.ViewHolder holder, int currentFooterStatus) { FooterViewHolder footViewHolder = (FooterViewHolder) holder; switch (currentFooterStatus) { case UpLoadingRecyclerView.FooterStatus.FOOTER_PULL_UP_LOADING: footViewHolder.footerText.setText(R.string.ad_pull_up_load_more); footViewHolder.footerProgress.setVisibility(View.GONE); break; case UpLoadingRecyclerView.FooterStatus.FOOTER_LOADING: footViewHolder.footerText.setText(R.string.ad_loading_more_for_you); footViewHolder.footerProgress.setVisibility(View.VISIBLE); break; case UpLoadingRecyclerView.FooterStatus.FOOTER_ERROR: footViewHolder.footerText.setText(R.string.ad_network_anomaly_click_reload); footViewHolder.footerProgress.setVisibility(View.GONE); break; case UpLoadingRecyclerView.FooterStatus.FOOTER_NO_MORE_DATA: footViewHolder.footerText.setText(R.string.ad_Theres_nothing_more); footViewHolder.footerProgress.setVisibility(View.GONE); break; } } @Override public int getItemViewCount() { return mList.size(); } public void setListener(OnClickListener listener) { this.mListener = listener; } public interface OnClickListener { void onClickItem(HomeVideoBean bean); void onClickFooter(); } public static class HomeVideoViewHolder extends RecyclerView.ViewHolder { ImageView icon; TextView time; TextView content; SimpleDraweeView videoImage; public HomeVideoViewHolder(@NonNull View itemView) { super(itemView); icon = itemView.findViewById(R.id.icon); time = itemView.findViewById(R.id.time); content = itemView.findViewById(R.id.content); videoImage = itemView.findViewById(R.id.videoImage); } } public static class FooterViewHolder extends RecyclerView.ViewHolder { ProgressBar footerProgress; TextView footerText; public FooterViewHolder(@NonNull View itemView) { super(itemView); footerProgress = itemView.findViewById(R.id.footer_progress); footerText = itemView.findViewById(R.id.footer_text); } } }
activity的关键部分
//数据来源 mHomeVideoViewModel.getHomeVideoList().observe(this,new Observer<Result<List<HomeVideoBean>>>() { @Override public void onChanged (Result < List < HomeVideoBean >> result) { if (result.getCode() != 200 && result.getCode() != 0) { //服务器加载数据异常 Toast.makeText(HomeVideoActivity.this, "" + result.getMsg(), Toast.LENGTH_SHORT).show(); if (mCurrentPage == 1) { //如果是第一页数据就直接隐藏整个列表 mRecyclerMessageVideo.setVisibility(View.GONE); } else { //如果是其他页数据,就在页尾显示网络异常 mAdapter.setFooterNetWorkError(); } return; } if (mCurrentPage == 1) { //如果页数等于1,那就是首次数据 if (result.getData() != null && !result.getData().isEmpty()) { mAdapter.refreshData(result.getData()); //刷新数据 } else { mRecyclerMessageVideo.setVisibility(View.GONE); } } else { mAdapter.addData(result.getData()); //添加数据 } if (result.getData().size() < 10) { //判断获取的数据熟练是否满足10个达到一页内容 mAdapter.setFooterNoMoreData(); //如果不满足,就显示没有更多数据了 } else { mAdapter.setFooterPullUpLoading(); //如果满足,就显示上拉加载更多数据 } } }); mRecyclerMessageVideo.setOnUpPullLoadListener(new UpLoadingRecyclerView.OnUpPullLoadListener(){ @Override public void OnUpPullLoad () { //上拉加载数据 mAdapter.setFooterLoading(); //将尾页显示为加载中 mCurrentPage++; mHomeVideoViewModel.postHomeVideoList(mRequestTime, mDeviceSn, mCurrentPage, 10); //请求数据 } }); mAdapter.setListener(new HomeVideoAdapter.OnClickListener(){ @Override public void onClickItem (HomeVideoBean bean){ //item点击 } @Override public void onClickFooter () { if (mAdapter.isFooterNetWorkError()) { //如果尾页显示网络异常就允许点击,重新加载数据 mHomeVideoViewModel.postHomeVideoList(mRequestTime, mDeviceSn, mCurrentPage, 10); } } });
End
本文来自博客园,作者:观心静 ,转载请注明原文链接:https://www.cnblogs.com/guanxinjing/p/13204403.html
本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。