说明:该自定义RecyclerView只适用于layoutManager为LinearLayoutManager的情况,使用的还是RecyclerView.Adapter。
1、编写layout文件
2、定义HeaderView
3、定义FooterView
4、Java代码实现
package com.shbj.refreashrvdemo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.shbj.refreashrvdemo.ui.RefreashRecyclerView;
import java.util.ArrayList;
public class Demo1Fragment extends Fragment {
private final String TAG = "Demo1Fragment";
private ArrayList mStrings;
private final int TYPE_REFRESH = 1;
private final int TYPE_LOAD = 2;
private final int TYPE_NO_LOAD_MORE = 3;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case TYPE_REFRESH:
mRv.refreshEnd();//刷新完成后需调用refreshEnd,更新HeaderView显示状态
mDemo1Adapter.setDatas(mStrings);
//由于自定义RecycleView中使用了自定义的adapter所以数据改变时需调用自定义adapter的notifyDataSetChanged
mRv.getAdapter().notifyDataSetChanged();
TextView tvHeader = mHeaderView.findViewById(R.id.tv_refresh);
LinearLayout llRefreshing = mHeaderView.findViewById(R.id.ll_refreshing);
tvHeader.setVisibility(View.VISIBLE);
llRefreshing.setVisibility(View.INVISIBLE);
break;
case TYPE_LOAD:
mDemo1Adapter.setDatas(mStrings);
mRv.getAdapter().notifyDataSetChanged();
TextView tvLoad = mFooterView.findViewById(R.id.tv_load);
LinearLayout llLoading = mFooterView.findViewById(R.id.ll_loading);
tvLoad.setVisibility(View.VISIBLE);
llLoading.setVisibility(View.INVISIBLE);
break;
case TYPE_NO_LOAD_MORE:
mRv.removeOnLoadMoreListener();//当没有更多数据时可移除加载更多监听
tvLoad = mFooterView.findViewById(R.id.tv_load);
llLoading = mFooterView.findViewById(R.id.ll_loading);
tvLoad.setVisibility(View.VISIBLE);
llLoading.setVisibility(View.INVISIBLE);
tvLoad.setText("没有更多数据了");
break;
}
}
};
private RefreashRecyclerView mRv;
private Demo1Adapter mDemo1Adapter;
private View mHeaderView;
private View mFooterView;
private int mLoadCount;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
View view = View.inflate(getContext(), R.layout.fragment_demo1, null);
mStrings = new ArrayList<>();
for (int i = 0; i < 50; i++) {//初始数据
mStrings.add("条目 " + i);
}
mRv = view.findViewById(R.id.rv);
mRv.setLayoutManager(new LinearLayoutManager(getContext()));
mRv.addItemDecoration(new DividerItemDecoration(getContext(), DividerItemDecoration.VERTICAL));
mHeaderView = LayoutInflater.from(this.getContext()).inflate(R.layout.item_header, mRv, false);
mRv.setHeaderView(mHeaderView);//设置HeaderView,需在setLayoutManager后设置否则会报错
mFooterView = LayoutInflater.from(this.getContext()).inflate(R.layout.item_footer, mRv, false);
mRv.setFooterView(mFooterView);//设置FooterView
mDemo1Adapter = new Demo1Adapter(getContext(), mStrings);
mRv.setAdapter(mDemo1Adapter);//设置adapter,照样继承的是RecycleView中自带的adapter
mRv.setOnRefreshListener(new RefreashRecyclerView.OnRefreshListener() {//设置下拉刷新监听
@Override
public void onStartRefresh() {
TextView tvHeader = mHeaderView.findViewById(R.id.tv_refresh);
LinearLayout llRefreshing = mHeaderView.findViewById(R.id.ll_refreshing);
tvHeader.setVisibility(View.INVISIBLE);
llRefreshing.setVisibility(View.VISIBLE);
refresh();//监听到开始刷新时调用刷新函数
}
});
mRv.setOnPullDownListener(new RefreashRecyclerView.OnPullDownListener() {//设置下拉过程的监听
@Override
public void onPullDownProgress(float progress) {//获取下拉的占比,一些特殊要求可能会用到,比如下面实现了下拉过程中字体逐渐变大
if (progress > 1) {
progress = 1;
}
TextView tvHeader = mHeaderView.findViewById(R.id.tv_refresh);
tvHeader.setTextSize(15 + 20 * progress);
}
});
mRv.setOnLoadMoreListener(new RefreashRecyclerView.OnLoadMoreListener() {//设置上拉加载更多的监听
@Override
public void onLoadMoreStart() {
TextView tvLoad = mFooterView.findViewById(R.id.tv_load);
LinearLayout llLoading = mFooterView.findViewById(R.id.ll_loading);
tvLoad.setVisibility(View.INVISIBLE);
llLoading.setVisibility(View.VISIBLE);
loadMore();//监听到开始加载时调用加载更多函数
}
});
return view;
}
private void refresh() {
new Thread(new Runnable() {
@Override
public void run() {
SystemClock.sleep(3000);
mStrings.clear();
for (int i = 0; i < 50; i++) {
mStrings.add("栏目 " + i);
}
mHandler.sendEmptyMessage(TYPE_REFRESH);
}
}).start();
}
private void loadMore() {
mLoadCount++;
new Thread(new Runnable() {
@Override
public void run() {
SystemClock.sleep(3000);
if (mLoadCount == 3) {//模拟没有更多数据
mHandler.sendEmptyMessage(TYPE_NO_LOAD_MORE);
} else {
for (int i = 0; i < 20; i++) {
mStrings.add("新栏目 " + i);
}
Log.d(TAG, "run: loadMore");
mHandler.sendEmptyMessage(TYPE_LOAD);
}
}
}).start();
}
}
5、定义adapter,使用的还是RecyclerView.Adapter
package com.shbj.refreashrvdemo;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.List;
public class Demo1Adapter extends RecyclerView.Adapter {
private Context mContext;
private List mDatas;
public Demo1Adapter(Context context, List datas){
mContext = context;
mDatas = datas;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.item_normal, parent, false);
RecyclerView.ViewHolder holder = new NormalHolder(view);
return holder;
}
public void setDatas(List datas){
mDatas=datas;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
((NormalHolder)holder).setData(position);
}
@Override
public int getItemCount() {
if (mDatas != null) {
return mDatas.size();
}
return 0;
}
class NormalHolder extends RecyclerView.ViewHolder {
private View mItemView;
public NormalHolder(View itemView) {
super(itemView);
mItemView = itemView;
}
public void setData(int postion) {
((TextView) mItemView).setText(mDatas.get(postion));
}
}
}
1、在onlayout时获取HeaderView的高度,并修改HeaderView的TopMargin值使其隐藏
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
Log.d(TAG, "onLayout: " + sHeaderViewMeasuredHeight);
if (isFristLayout) {
//将sHeaderViewMeasuredHeight设置为static,只要是为了防止页面间切换出现bug
if (sHeaderViewMeasuredHeight == 0) {//只有当第一次layout时才会为sHeaderViewMeasuredHeight赋值
sHeaderViewMeasuredHeight = mHeaderView.getMeasuredHeight();//获取HeaderView的高度
}
updateMargin(-sHeaderViewMeasuredHeight);//修改HeaderView的TopMargin值使其隐藏
}
}
2、重写onTouchEvent,实现下拉刷新和上拉加载的效果
@Override
public boolean onTouchEvent(MotionEvent e) {
//下拉刷新处理
if (mHeaderView == getChildAt(0)) {
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
mDownX = e.getX();
mDownY = e.getY();
break;
case MotionEvent.ACTION_MOVE:
float moveX = e.getX();
float moveY = e.getY();
mDx = moveX - mDownX;
mDy = moveY - mDownY;
if (Math.abs(mDy) > Math.abs(mDx) && mDy > 0) {
if (mDy < 2 * sHeaderViewMeasuredHeight) {//小于两倍height时,逐渐修改TopMargin,使HeaderView逐渐显现出来
updateMargin(-sHeaderViewMeasuredHeight + (int) mDy);
if (mOnPullDownListener != null) {
mOnPullDownListener.onPullDownProgress(mDy / sHeaderViewMeasuredHeight);//将占比返回给监听者
}
}
}
break;
case MotionEvent.ACTION_UP:
float upX = e.getX();
float upY = e.getY();
mDx = upX - mDownX;
mDy = upY - mDownY;
if (Math.abs(mDy) > Math.abs(mDx) && mDy > 0 && mHeaderView.getTop() > -sHeaderViewMeasuredHeight) {
if (mDy < sHeaderViewMeasuredHeight * 2 / 3) {//小于两倍height时,TopMargin置为-sHeaderViewMeasuredHeight,使其隐藏
updateMargin(-sHeaderViewMeasuredHeight);
} else {//否则使其完全显现
updateMargin(0);
if (mOnRefreshListener != null) {
//下拉释放后开始刷新
mOnRefreshListener.onStartRefresh();//通知监听者开始刷新
}
}
}
break;
}
}
//上拉加载处理
if (mFooterView == getChildAt(getChildCount() - 1)) {
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
mDownX = e.getX();
mDownY = e.getY();
break;
case MotionEvent.ACTION_UP:
float upX = e.getX();
float upY = e.getY();
mDx = upX - mDownX;
mDy = upY - mDownY;
if (Math.abs(mDy) > Math.abs(mDx) && mDy < -80) {//上拉加载时,mDy < -80可以通过此处调节加载的灵敏度,值越小上拉所需的距离约大
if (mOnLoadMoreListener != null) {
mOnLoadMoreListener.onLoadMoreStart();//通知监听者开始加载
}
}
break;
}
}
return super.onTouchEvent(e);
}
3、刷新完成后,处理逻辑
//刷新结束后调用该方法隐藏HeaderView
public void refreshEnd() {
if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
updateMargin(-sHeaderViewMeasuredHeight);
} else {
mHeaderView.post(new Runnable() {
@Override
public void run() {
updateMargin(-sHeaderViewMeasuredHeight);
}
});
}
}
4、定义各类监听接口
//下拉刷新的进程监听,可以获取到下拉过程中下拉的占比
private OnPullDownListener mOnPullDownListener;
public void setOnPullDownListener(OnPullDownListener onPullDownListener) {
mOnPullDownListener = onPullDownListener;
}
public interface OnPullDownListener {
void onPullDownProgress(float progress);
}
//下拉刷新的监听
private OnRefreshListener mOnRefreshListener;
public void setOnRefreshListener(OnRefreshListener onRefreshListener) {
mOnRefreshListener = onRefreshListener;
}
public interface OnRefreshListener {
void onStartRefresh();
}
//加载更多监听
private OnLoadMoreListener mOnLoadMoreListener;
public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) {
mOnLoadMoreListener = onLoadMoreListener;
}
//如果没有更多的加载项目可以移除OnLoadMoreListener
public void removeOnLoadMoreListener() {
mOnLoadMoreListener = null;
}
public interface OnLoadMoreListener {
void onLoadMoreStart();
}
5、设置HeaderView和FooterView
public void setHeaderView(View headerView) {
mHeaderView = headerView;
}
public void setFooterView(View footerView) {
mFooterView = footerView;
}
6、自定义Adapter
//自定义adapter加入header和footer
private class RefreashAdapter extends RecyclerView.Adapter {
private final int HEADER_TYPE = 0;
private final int NORMAL_TYPE = 1;
private final int FOOTER_TYPE = 2;
private Adapter mAdapter;
public RefreashAdapter(Adapter adapter) {
mAdapter = adapter;
}
@Override
public int getItemViewType(int position) {
int type = 0;
if (position == 0) {
type = HEADER_TYPE;
} else if (position == getItemCount() - 1) {
type = FOOTER_TYPE;
} else {
type = NORMAL_TYPE;
}
return type;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
RecyclerView.ViewHolder holder;
switch (viewType) {
case HEADER_TYPE:
holder = new HeaderHolder(mHeaderView);
break;
case FOOTER_TYPE:
holder = new FooterHolder(mFooterView);
break;
default:
holder = mAdapter.onCreateViewHolder(parent, viewType);
break;
}
return holder;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (getItemViewType(position) == NORMAL_TYPE) {
mAdapter.onBindViewHolder(holder, position - 1);
}
}
@Override
public int getItemCount() {
return mAdapter.getItemCount() + 2;
}
class HeaderHolder extends RecyclerView.ViewHolder {
public HeaderHolder(View itemView) {
super(itemView);
}
}
class FooterHolder extends RecyclerView.ViewHolder {
public FooterHolder(View itemView) {
super(itemView);
}
}
}
点击打开链接