分享下android 一个Listview下拉刷新的二次封装(第一次修订)
来源:互联网 发布:酷宝数据 造假 编辑:程序博客网 时间:2024/06/05 16:00
今天我在一些博客上面发现一个问题,现在基本主流已经放弃了使用ListView,srollview,转而用一个新的控件recycleview去显示列表。优点嘛,目前没实践过,不过有人安利我说,“这个猴赛雷,猴好用,代码简单,方便加特效,而且最低支持到4.0的哟,亲!!!”。好吧,我准备下个项目用,那接下来我就来点干货。接下来我为大家安利一个同时支持上拉刷新和下拉刷新的自定义控件,一个对recyclerview进行二次封装的一个View:自定义RecyclerView实现自动加载
为了实现自动加载更多的功能,我选择自定义实现一个特殊的RecyclerView来实现,网络上也有自定义一个包含RecyclerView和loading_more的布局,现在我想试试adapter处理的方式,所以有了这个自定义实现类
java片段1: RecyclerView实现LoadMoreRecyclerView
/**
* Alipay.com Inc.
* Copyright (c) 2004-2015 All Rights Reserved.
*/
package com.leaf8.alicx.myapplication;
import android.content.Context;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
/**
* 支持上拉加载更多的
*
* @author 肖肖
* @version
*/
public class LoadMoreRecyclerView extends RecyclerView {
/**
* item 类型
*/
public final static int TYPE_NORMAL = 0;
public final static int TYPE_HEADER = 1;//头部–支持头部增加一个headerView
public final static int TYPE_FOOTER = 2;//底部–往往是loading_more
public final static int TYPE_LIST = 3;//代表item展示的模式是list模式
public final static int TYPE_STAGGER = 4;//代码item展示模式是网格模式
private boolean mIsFooterEnable = false;//是否允许加载更多/** * 自定义实现了头部和底部加载更多的adapter */private AutoLoadAdapter mAutoLoadAdapter;/** * 标记是否正在加载更多,防止再次调用加载更多接口 */private boolean mIsLoadingMore;/** * 标记加载更多的position */private int mLoadMorePosition;/** * 加载更多的监听-业务需要实现加载数据 */private LoadMoreListener mListener;public LoadMoreRecyclerView(Context context) { super(context); init();}public LoadMoreRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); init();}public LoadMoreRecyclerView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init();}/** * 初始化-添加滚动监听 * <p/> * 回调加载更多方法,前提是 * <pre> * 1、有监听并且支持加载更多:null != mListener && mIsFooterEnable * 2、目前没有在加载,正在上拉(dy>0),当前最后一条可见的view是否是当前数据列表的最好一条--及加载更多 * </pre> */private void init() { super.addOnScrollListener(new OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); if (null != mListener && mIsFooterEnable && !mIsLoadingMore && dy > 0) { int lastVisiblePosition = getLastVisiblePosition(); if (lastVisiblePosition + 1 == mAutoLoadAdapter.getItemCount()) { setLoadingMore(true); mLoadMorePosition = lastVisiblePosition; mListener.onLoadMore(); } } } });}/** * 设置加载更多的监听 * * @param listener */public void setLoadMoreListener(LoadMoreListener listener) { mListener = listener;}/** * 设置正在加载更多 * * @param loadingMore */public void setLoadingMore(boolean loadingMore) { this.mIsLoadingMore = loadingMore;}/** * 加载更多监听 */public interface LoadMoreListener { /** * 加载更多 */ void onLoadMore();}/** * */public class AutoLoadAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { /** * 数据adapter */ private RecyclerView.Adapter mInternalAdapter; private boolean mIsHeaderEnable; private int mHeaderResId; public AutoLoadAdapter(RecyclerView.Adapter adapter) { mInternalAdapter = adapter; mIsHeaderEnable = false; } @Override public int getItemViewType(int position) { int headerPosition = 0; int footerPosition = getItemCount() - 1; if (headerPosition == position && mIsHeaderEnable && mHeaderResId > 0) { return TYPE_HEADER; } if (footerPosition == position && mIsFooterEnable) { return TYPE_FOOTER; } /** * 这么做保证layoutManager切换之后能及时的刷新上对的布局 */ if (getLayoutManager() instanceof LinearLayoutManager) { return TYPE_LIST; } else if (getLayoutManager() instanceof StaggeredGridLayoutManager) { return TYPE_STAGGER; } else { return TYPE_NORMAL; } } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == TYPE_HEADER) { return new HeaderViewHolder(LayoutInflater.from(parent.getContext()).inflate( mHeaderResId, parent, false)); } if (viewType == TYPE_FOOTER) { return new FooterViewHolder( LayoutInflater.from(parent.getContext()).inflate( R.layout.list_foot_loading, parent, false)); } else { // type normal return mInternalAdapter.onCreateViewHolder(parent, viewType); } } public class FooterViewHolder extends RecyclerView.ViewHolder { public FooterViewHolder(View itemView) { super(itemView); } } public class HeaderViewHolder extends RecyclerView.ViewHolder { public HeaderViewHolder(View itemView) { super(itemView); } } @Override public void onBindViewHolder(ViewHolder holder, int position) { int type = getItemViewType(position); if (type != TYPE_FOOTER && type != TYPE_HEADER) { mInternalAdapter.onBindViewHolder(holder, position); } } /** * 需要计算上加载更多和添加的头部俩个 * * @return */ @Override public int getItemCount() { int count = mInternalAdapter.getItemCount(); if (mIsFooterEnable) count++; if (mIsHeaderEnable) count++; return count; } public void setHeaderEnable(boolean enable) { mIsHeaderEnable = enable; } public void addHeaderView(int resId) { mHeaderResId = resId; }}@Overridepublic void setAdapter(RecyclerView.Adapter adapter) { if (adapter != null) { mAutoLoadAdapter = new AutoLoadAdapter(adapter); } super.swapAdapter(mAutoLoadAdapter, true);}/** * 切换layoutManager * * 为了保证切换之后页面上还是停留在当前展示的位置,记录下切换之前的第一条展示位置,切换完成之后滚动到该位置 * 另外切换之后必须要重新刷新下当前已经缓存的itemView,否则会出现布局错乱(俩种模式下的item布局不同), * RecyclerView提供了swapAdapter来进行切换adapter并清理老的itemView cache * * @param layoutManager */public void switchLayoutManager(LayoutManager layoutManager) { int firstVisiblePosition = getFirstVisiblePosition();
// getLayoutManager().removeAllViews();
setLayoutManager(layoutManager);
//super.swapAdapter(mAutoLoadAdapter, true);
getLayoutManager().scrollToPosition(firstVisiblePosition);
}
/** * 获取第一条展示的位置 * * @return */private int getFirstVisiblePosition() { int position; if (getLayoutManager() instanceof LinearLayoutManager) { position = ((LinearLayoutManager) getLayoutManager()).findFirstVisibleItemPosition(); } else if (getLayoutManager() instanceof GridLayoutManager) { position = ((GridLayoutManager) getLayoutManager()).findFirstVisibleItemPosition(); } else if (getLayoutManager() instanceof StaggeredGridLayoutManager) { StaggeredGridLayoutManager layoutManager = (StaggeredGridLayoutManager) getLayoutManager(); int[] lastPositions = layoutManager.findFirstVisibleItemPositions(new int[layoutManager.getSpanCount()]); position = getMinPositions(lastPositions); } else { position = 0; } return position;}/** * 获得当前展示最小的position * * @param positions * @return */private int getMinPositions(int[] positions) { int size = positions.length; int minPosition = Integer.MAX_VALUE; for (int i = 0; i < size; i++) { minPosition = Math.min(minPosition, positions[i]); } return minPosition;}/** * 获取最后一条展示的位置 * * @return */private int getLastVisiblePosition() { int position; if (getLayoutManager() instanceof LinearLayoutManager) { position = ((LinearLayoutManager) getLayoutManager()).findLastVisibleItemPosition(); } else if (getLayoutManager() instanceof GridLayoutManager) { position = ((GridLayoutManager) getLayoutManager()).findLastVisibleItemPosition(); } else if (getLayoutManager() instanceof StaggeredGridLayoutManager) { StaggeredGridLayoutManager layoutManager = (StaggeredGridLayoutManager) getLayoutManager(); int[] lastPositions = layoutManager.findLastVisibleItemPositions(new int[layoutManager.getSpanCount()]); position = getMaxPosition(lastPositions); } else { position = getLayoutManager().getItemCount() - 1; } return position;}/** * 获得最大的位置 * * @param positions * @return */private int getMaxPosition(int[] positions) { int size = positions.length; int maxPosition = Integer.MIN_VALUE; for (int i = 0; i < size; i++) { maxPosition = Math.max(maxPosition, positions[i]); } return maxPosition;}/** * 添加头部view * * @param resId */public void addHeaderView(int resId) { mAutoLoadAdapter.addHeaderView(resId);}/** * 设置头部view是否展示 * @param enable */public void setHeaderEnable(boolean enable) { mAutoLoadAdapter.setHeaderEnable(enable);}/** * 设置是否支持自动加载更多 * * @param autoLoadMore */public void setAutoLoadMoreEnable(boolean autoLoadMore) { mIsFooterEnable = autoLoadMore;}/** * 通知更多的数据已经加载 * * 每次加载完成之后添加了Data数据,用notifyItemRemoved来刷新列表展示, * 而不是用notifyDataSetChanged来刷新列表 * * @param hasMore */public void notifyMoreFinish(boolean hasMore) { setAutoLoadMoreEnable(hasMore); getAdapter().notifyItemRemoved(mLoadMorePosition); mIsLoadingMore = false;}
}
实现原理是利用RecyclerView.Adapter的getItemType来区别不一样的item布局,这里是实现了一个支持头部和底部的额外itemVIew的apdater壳子,将数据的adapter放到这个壳子中去代理,保证业务方实现的adapter的纯净。
另外LoadMoreRecyclerView管理了5个itemType,除了TYPE_HEADER和TYPE_FOOTER之外,其余三个会传递给业务方的onCreateViewHolder方法,业务方根据这个参数决定使用布局,当然业务方页可以用自己的方式实现判断条件:
java片段2: 业务方可能的onCreateViewHolder实现
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == LoadMoreRecyclerView.TYPE_STAGGER) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.fragment_item_staggel, parent, false);
return new StaggerViewHolder(view);
} else {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.fragment_item, parent, false);
return new ViewHolder(view);
}
}
实现下拉刷新
下拉刷新的实现,我也是直接用了google提供的support-v4包种的SwipeRefreshLayout,只要实现下拉刷新的获取数据动作即可,
layout1:
- 分享下android 一个Listview下拉刷新的二次封装(第一次修订)
- 分享下android 一个Listview下拉刷新的二次封装
- Android listview下拉刷新,上拉加载(发现一个比较好用的,和大家分享下)
- android listview 的下拉刷新
- Android listView的下拉刷新
- Android ListView的下拉刷新
- [分享]新封装的一个实现无刷新连动下拉列表类
- 自己实现一个下拉刷新的ListView
- 分享一个可下拉刷新的ScrollView
- Android ListView下拉刷新
- android Listview下拉刷新
- Android ListView下拉刷新
- Android-ListView 下拉刷新
- android listview下拉刷新!
- android listview下拉刷新
- Android ListView下拉刷新
- Android ListView 下拉刷新
- Android ListView下拉刷新
- python学习笔记(面向对象)
- 设置居中
- HDU 1864最大报销额(01背包)
- 自定义UISearchBar外观
- POJ-2226
- 分享下android 一个Listview下拉刷新的二次封装(第一次修订)
- Java 中正确使用 hashCode 和 equals 方法
- 大公司里怎样开发和部署前端代码
- devexpress中gridview控件编辑时改变输入法状态
- stm32 BOOTLOADER 导出函数给APP调用出现malloc无法分配内存的问题
- ROS学习之 roscpp内部架构概况
- python编码的转换
- 数组中sort
- C# SmtpClient 遇到的两个Exception