本文注意记录一些零碎的东西
闲来无事,自定义了一个下拉刷新上滑加载更多的RecycleView,虽说网络上比我写得好的太多了,小小纪录一下
RefreshRecycleView.java
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.ColorRes;
import android.support.annotation.IdRes;
import android.support.annotation.Nullable;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import java.util.List;
/**
* 上拉刷新 下滑加载更多
* 暂时只支持 LinearLayoutManager
* 原理:
* 下滑 使用 SwipeRefreshLayout
* 上拉 使用 屏幕上面的顶部item和顶部item相关,获取到RecyclerView列表中Item View的个数
* ---findFirstVisibleItemPosition(),findFirstCompletlyVisibleItemPosition()
* ---findLastVisibleItemPosition(),findLastCompletlyVisibleItemPosition()
* ---getItemCount()
* Created by slack
* on 17/3/8 下午1:58.
* how to use :
* 1.mRefreshRecycleView = (RefreshRecycleView) findViewById(R.id.xxx);
* 2.mRefreshRecycleView.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false));
* 3.mRefreshRecycleView.setAdapter(mContactsAdapter);
*/
public class RefreshRecycleView extends FrameLayout {
private SwipeRefreshLayout mSwipeRefreshLayout;
private RecyclerView mRecyclerView;
private LinearLayoutManager mLinearLayoutManager;
private RecyclerView.Adapter mAdapter;
private Handler mHandler = new Handler(Looper.getMainLooper());
private RefreshListener mRefreshListener;
private int mLastVisibleItemPosition;// 最后一个可见 item position
public RefreshRecycleView(Context context) {
this(context,null);
}
public RefreshRecycleView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public RefreshRecycleView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initView(context);
}
/**
* important !!!
* RecyclerView.setLayoutManager
* @param manager manager
* @return
*/
public RefreshRecycleView setLayoutManager(LinearLayoutManager manager){
mLinearLayoutManager = manager;
mRecyclerView.setLayoutManager(manager);
return this;
}
/**
* important !!!
* RecyclerView.setAdapter
* @param adapter adapter
* @return
*/
public RefreshRecycleView setAdapter(RecyclerView.Adapter adapter){
mAdapter = adapter;
mRecyclerView.setAdapter(adapter);
return this;
}
/**
* 异步需要手动 关闭 下拉 刷新
*/
public void finishRefresh() {
mHandler.post(new Runnable() {
@Override
public void run() {
mAdapter.notifyDataSetChanged();
mSwipeRefreshLayout.setRefreshing(false);
//
}
});
}
/**
* 设置进度条的颜色主题,最多设置四种
* @param colorResIds ids
* @return
*/
public RefreshRecycleView setRefreshColorResources(@ColorRes int... colorResIds){
mSwipeRefreshLayout.setColorSchemeResources(colorResIds);
return this;
}
/**
* 设置滑动 刷新 监听
* @param l RefreshListener
* @return
*/
public RefreshRecycleView setRefreshListener(RefreshListener l){
mRefreshListener = l;
return this;
}
public RecyclerView getRecyclerView(){
return mRecyclerView;
}
private void initView(Context context) {
mSwipeRefreshLayout = new SwipeRefreshLayout(context);
mRecyclerView = new RecyclerView(context);
mSwipeRefreshLayout.addView(mRecyclerView);
addView(mSwipeRefreshLayout);
initRefreshLayout();
initRecyclerView();
}
private void initRecyclerView() {
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
mRecyclerView.setHasFixedSize(true);
mRecyclerView.addOnScrollListener(mOnScrollListener);
}
private void initRefreshLayout() {
/**
* 设置刷新时动画的颜色,可以设置4个
*/
mSwipeRefreshLayout.setColorSchemeResources(
android.R.color.holo_blue_light,
android.R.color.holo_red_light,
android.R.color.holo_orange_light,
android.R.color.holo_green_light);
/**
* 设置下拉监听,当用户下拉的时候会去执行回调
*/
mSwipeRefreshLayout.setOnRefreshListener(mOnRefreshListener);
/**
* 这句话是为了,第一次进入页面的时候显示加载进度条
* 调整进度条距离屏幕顶部的距离 (boolean scale, int start, int end)
*/
mSwipeRefreshLayout.setProgressViewOffset(
false,
0,
(int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,24,getResources().getDisplayMetrics()));
/**
* setRefreshing(boolean refreshing) 设置SwipeRefreshLayout当前是否处于刷新状态,
* 一般是在请求数据的时候设置为true,在数据被加载到View中后,设置为false。
*/
}
private SwipeRefreshLayout.OnRefreshListener mOnRefreshListener =
new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
if(mRefreshListener != null) {
new Thread(new Runnable() {
@Override
public void run() {
if(mRefreshListener.onPullToRefresh()) {
finishRefresh();
}
}
}).start();
}else {
finishRefresh();
}
}
};
private RecyclerView.OnScrollListener mOnScrollListener =
new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE &&
mLastVisibleItemPosition + 1 == mAdapter.getItemCount()) {
if(mRefreshListener != null){
new Thread(new Runnable() {
@Override
public void run() {
if(mRefreshListener.onUpGlideLoadMore()) {
finishRefresh();
}
}
}).start();
}else {
finishRefresh();
}
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
mLastVisibleItemPosition = mLinearLayoutManager.findLastVisibleItemPosition();
}
};
/**
* 如果需要 上滑加载更多 的 布局 adapter need
* extends this
* extends ItemViewHolder
* 原理 onCreateViewHolder(ViewGroup paren,int viewType) 第二个参数viewType,支持多套布局显示
*/
public static abstract class RefreshFootAdapter
extends RecyclerView.Adapter {
private final int TYPE_ITEM =0; //普通 Item View
private final int TYPE_FOOTER = 1; //底部 Foot View
private final String FootViewTag = "FootView";
private List> mDatas ;
protected LayoutInflater mLayoutInflater;
private Context mContext;
public RefreshFootAdapter(Context context, List> mDatas) {
mContext = context;
this.mDatas = mDatas;
mLayoutInflater = LayoutInflater.from(context);
}
/**
* 进行判断显示类型,来创建返回不同的View
*/
@Override
public T onCreateViewHolder(ViewGroup parent, int viewType) {
if(viewType==TYPE_ITEM){
return onItemView (parent, viewType);
}else if(viewType==TYPE_FOOTER){
return onFootView(parent, viewType);
}
return null;
}
/**
* return new ItemViewHolder(xxx)
*/
protected abstract T onItemView(ViewGroup parent, int viewType);
/**
* foot view
*/
protected abstract T onFootView(ViewGroup parent, int viewType);
/**
* 返回的Item数量在数据的基础上面+1,增加一项FootView布局项
*/
@Override
public int getItemCount() {
return mDatas == null ? 1 : mDatas.size() + 1;
}
/**
* 最后一个item设置为footerView
* position 0,1,2,3...
*/
@Override
public int getItemViewType(int position) {
if (position + 1 == getItemCount()) {
return TYPE_FOOTER;
} else {
return TYPE_ITEM;
}
}
@Override
public void onBindViewHolder(T holder, int position) {
holder.bindView(holder,position);
}
public abstract class BaseViewHolder extends RecyclerView.ViewHolder{
private View mView;
public BaseViewHolder(View itemView) {
super(itemView);
mView = itemView;
}
protected abstract void bindView(RecyclerView.ViewHolder holder,int pos);
protected View findViewById(@IdRes int id){
return mView.findViewById(id);
}
}
}
/**
* 方法都是在子线程里运行的
* return 是否 同步执行代码(true 同步获取数据,false 异步获取数据)
* 异步需要手动 关闭 下拉 刷新
*/
public interface RefreshListener{
boolean onPullToRefresh();
boolean onUpGlideLoadMore();
}
}
使用比较简单,直接把这个自定义文件拷贝了就好,需要注意的是 回调方法都是在 子线程里运行的,毕竟加载数据要么联网要么读取文件,不需要在主线程里执行,返回值的意思是判断是否在子线程里同步获取数据,
如果异步获取 返回 false,数据获取到后需要主动调用
mRefreshRecycleView.finishRefresh(); 刷新数据
如何使用:
final List data = new ArrayList(){
{
for (int i= 0;i<20;i++){
add("item " + i);
}
}
};
mRefreshRecycleView.setLayoutManager(
new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false));
mRefreshRecycleView.setAdapter(new ReshAdapter(mRefreshRecycleView.getContext(),data));
mRefreshRecycleView.setRefreshListener(new RefreshRecycleView.RefreshListener() {
@Override
public boolean onPullToRefresh() {
data.clear();
for (int i= 0;i<20;i++){
data.add("onPullToRefresh " + i);
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return true;
}
@Override
public boolean onUpGlideLoadMore() {
for (int i= 0;i<5;i++){
data.add("onUpGlideLoadMore " + i);
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return true;
}
});
里面封装了一个adapter ,主要是处理上滑时没有界面,如果不需要上滑加载更多的提示界面,直接无视下面的内容
自定义adapter extends RefreshRecycleView.RefreshFootAdapter 提供Item 布局 和 foot 提示正在加载数据的布局
class ReshAdapter extends RefreshRecycleView.RefreshFootAdapter {
private List mDatas;
ReshAdapter(Context context, List datas) {
super(context, datas);
this.mDatas = datas;
}
@Override
protected ReshViewHolder onItemView(ViewGroup parent, int viewType) {
return new ReshViewHolder(
mLayoutInflater.inflate(R.layout.item_contact,parent,false));
}
@Override
protected FootViewHolder onFootView(ViewGroup parent, int viewType) {
return new FootViewHolder(
mLayoutInflater.inflate(R.layout.item_contact,parent,false));
}
class ReshViewHolder extends BaseViewHolder{
private TextView textView;
public ReshViewHolder(View itemView) {
super(itemView);
textView = (TextView)findViewById(R.id.contact_name);
}
@Override
protected void bindView(RecyclerView.ViewHolder holder, int pos) {
textView.setText(mDatas.get(pos));
}
}
class FootViewHolder extends BaseViewHolder{
private TextView textView;
public FootViewHolder(View itemView) {
super(itemView);
textView = (TextView)findViewById(R.id.contact_name);
}
@Override
protected void bindView(RecyclerView.ViewHolder holder, int pos) {
textView.setText("loading more ...");
}
}
}