效果图
先是adapter:
import android.content.Context;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.example.refreshrecylerview.R;
import java.util.ArrayList;
import java.util.List;
/**
* Created by yebin on 2016/12/7.
*/
public class MyAdapeter extends RecyclerView.Adapter<MyAdapeter.MyHolder> {
private RecyclerView mRecyclerView;
private List<String> data = new ArrayList<>();
private Context mContext;
private View VIEW_FOOTER;
private View VIEW_HEADER;
//Type
private int TYPE_NORMAL = 1000;
private int TYPE_HEADER = 1001;
private int TYPE_FOOTER = 1002;
public MyAdapeter(List<String> data,Context mContext){
this.data=data;
this.mContext=mContext;
}
@Override
public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if(viewType==TYPE_HEADER){
return new MyHolder(VIEW_HEADER);
}else if(viewType==TYPE_FOOTER){
return new MyHolder(VIEW_FOOTER);
}else {
return new MyHolder(LayoutInflater.from(mContext).inflate(R.layout.item_recylerview,parent,false));
}
}
@Override
public void onBindViewHolder(MyHolder holder, int position) {
if(!isHeaderView(position)&&!isFooterView(position)){
if(haveHeaderView()){
position--;
}
TextView textView = (TextView) holder.itemView.findViewById(R.id.item_content);
textView.setText(data.get(position));
}
}
@Override
public int getItemCount() {
int count=(data==null?0:data.size());
if(haveHeaderView()){
count++;
}
if(haveFooterView()){
count++;
}
return count;
}
@Override
public int getItemViewType(int position) {
if(isHeaderView(position)){
return TYPE_HEADER;
}else if(isFooterView(position)){
return TYPE_FOOTER;
}else {
return TYPE_NORMAL;
}
}
public void addHeaderView(View headerView){
if (haveHeaderView()) {
throw new IllegalStateException("hearview has already exists!");
} else {
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
headerView.setLayoutParams(params);
VIEW_HEADER=headerView;
ifGridLayoutManager();
notifyItemInserted(0);
}
}
public void addFooterView(View footerView){
if (haveFooterView()) {
throw new IllegalStateException("footerView has already exists!");
} else {
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
footerView.setLayoutParams(params);
VIEW_FOOTER=footerView;
ifGridLayoutManager();
notifyItemInserted(getItemCount()-1);
}
}
private boolean isHeaderView(int position) {
return haveHeaderView()&&position==0;
}
private boolean isFooterView(int position) {
return haveFooterView()&&position==getItemCount()-1;
}
private boolean haveHeaderView() {
return VIEW_HEADER!=null;
}
private boolean haveFooterView() {
return VIEW_FOOTER!=null;
}
public static class MyHolder extends RecyclerView.ViewHolder{
public MyHolder(View view){
super(view);
}
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
try {
if(mRecyclerView==null||mRecyclerView!=recyclerView){
mRecyclerView=recyclerView;
}
ifGridLayoutManager();
}catch (Exception e){
e.printStackTrace();
}
}
private void ifGridLayoutManager() {
if(mRecyclerView==null){
return;
}
final RecyclerView.LayoutManager layoutManager = mRecyclerView.getLayoutManager();
if(layoutManager instanceof GridLayoutManager){
GridLayoutManager.SpanSizeLookup originSpanSizeLookup = ((GridLayoutManager) layoutManager).getSpanSizeLookup();
((GridLayoutManager) layoutManager).setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
return isHeaderView(position)||isFooterView(position)? ((GridLayoutManager) layoutManager).getSpanCount():1;
}
});
}
}
public View getHeaderView(){
return VIEW_HEADER;
}
public View getFooterView(){
return VIEW_FOOTER;
}
}
然后就是RefreshRecyclerView 这里只写了垂直方向的线性列表 没有考虑网格等其他布局
import android.content.Context;
import android.graphics.drawable.AnimationDrawable;
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.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.example.refreshrecylerview.R;
/**
* Created by yebin on 2016/12/7.
*/
public class RefreshRecyclerView extends RecyclerView {
//就是刷新的头
private LinearLayout headerView;
//刷新的头中可以隐藏部分
private View mPullDownHeaderView;
//隐藏部分高度
private int headerViewHeight;
private ImageView headerViewProgess;
private TextView headerViewMessage;
private View footerView;
private int footerViewHeight;
//headerView中的第二布局,用于添加其他头布局
private View secondHeaderView;
//监听
private onRefreshListner mOnRefreshListner;
private final int PULL_DOWN_REFRESH = 0; // 下拉刷新
private final int RELEASE_REFRESH = 1; // 释放更新
private final int REFRESHING = 2; // 加载中
private int currentState = PULL_DOWN_REFRESH; // 当前状态
private Boolean isLoardingMore=false;
private int mRecyclerViewYOnScreen=-1;
private int downY = -1;
private LinearLayoutManager mLinearLayoutManager;
private MyAdapeter mMyAdapeter;
public RefreshRecyclerView(Context context){
this(context,null);
}
public RefreshRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
//默认只能是垂直的。
mLinearLayoutManager = new LinearLayoutManager(context);
mLinearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
setLayoutManager(mLinearLayoutManager);
}
@Override
public void setAdapter(Adapter adapter) {
super.setAdapter(adapter);
if(adapter instanceof MyAdapeter){
mMyAdapeter= ((MyAdapeter) adapter);
initHeaderView(mMyAdapeter);
initFooterView(mMyAdapeter);
}
}
private void initFooterView(MyAdapeter adapter) {
footerView=adapter.getFooterView();
footerView.measure(0,0);
footerViewHeight=footerView.getMeasuredHeight();
footerView.setPadding(0,-footerViewHeight,0,0);
this.setOnScrollListener(new MyScrollListner());
}
private void initHeaderView(MyAdapeter adapter) {
headerView= (LinearLayout) adapter.getHeaderView();
if(headerView!=null){
headerViewProgess = (ImageView) headerView.findViewById(R.id.progress_view_loading);
headerViewMessage = (TextView) headerView.findViewById(R.id.progress_view_message);
mPullDownHeaderView= headerView.findViewById(R.id.ll_pull_down_header_view);
mPullDownHeaderView.measure(0,0);
headerViewHeight=mPullDownHeaderView.getMeasuredHeight();
mPullDownHeaderView.setPadding(0,-headerViewHeight,0,0);
}
}
public void addSecondHeaderView(View secondHeaderView){
this.secondHeaderView=secondHeaderView;
headerView.addView(secondHeaderView);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
downY = (int) ev.getY();
break;
case MotionEvent.ACTION_MOVE:
if (downY == -1) {
downY = (int) ev.getY();
}
int moveY= (int) ev.getY();
int diffY=moveY-downY;
if (currentState == REFRESHING) {
break;
}
if (!isDisplaySecondHeaderView()) {
break;
}
if(diffY>0){
int paddingTop=-headerViewHeight+diffY/3;
if(paddingTop>0&¤tState!=RELEASE_REFRESH){
currentState=RELEASE_REFRESH;
refreshHeadViewState();
}else if(paddingTop<0&¤tState!=PULL_DOWN_REFRESH){
currentState=PULL_DOWN_REFRESH;
refreshHeadViewState();
}
mPullDownHeaderView.setPadding(0,paddingTop,0,0);
}
break;
case MotionEvent.ACTION_UP:
downY=-1;
if(currentState==PULL_DOWN_REFRESH){
mPullDownHeaderView.setPadding(0,-headerViewHeight,0,0);
}else if(currentState==RELEASE_REFRESH){
currentState=REFRESHING;
refreshHeadViewState();
mPullDownHeaderView.setPadding(0,0,0,0);
if(mOnRefreshListner!=null){
mOnRefreshListner.onPullDownRefresh();
}
}
break;
default:
break;
}
return super.onTouchEvent(ev);
}
public boolean isDisplaySecondHeaderView() {
int[] laction=new int[2];
if(mRecyclerViewYOnScreen==-1){
getLocationOnScreen(laction);
mRecyclerViewYOnScreen=laction[1];
}
secondHeaderView.getLocationOnScreen(laction);
int secondHeaderViewYOnScreen = laction[1];
return mRecyclerViewYOnScreen<=secondHeaderViewYOnScreen;
}
private void refreshHeadViewState(){
switch (currentState){
case PULL_DOWN_REFRESH:
stopProgress();
headerViewMessage.setText("下拉刷新");
break;
case REFRESHING:
startProgress();
headerViewMessage.setText("加载中。。。。");
break;
case RELEASE_REFRESH:
stopProgress();
headerViewMessage.setText("释放更新");
break;
default:
break;
}
}
public interface onRefreshListner{
public void onPullDownRefresh();
public void onLoardingMore();
}
public void setOnRefreshListner(onRefreshListner listner){
this.mOnRefreshListner=listner;
}
/**
* 获取第一条展示的位置
*
* @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;
}
/**
* 获取最后一条展示的位置
*
* @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;
}
/**
* 获得当前展示最小的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;
}
private void startProgress(){
AnimationDrawable animations = (AnimationDrawable) headerViewProgess.getBackground();
animations.start();
}
private void stopProgress(){
AnimationDrawable animations = (AnimationDrawable) headerViewProgess.getBackground();
animations.stop();
}
public void onRefreshfinish(boolean isSuccess){
stopProgress();
if(isLoardingMore){
footerView.setPadding(0,-footerViewHeight,0,0);
isLoardingMore=false;
}else {
mPullDownHeaderView.setPadding(0,-headerViewHeight,0,0);
currentState=PULL_DOWN_REFRESH;
headerViewMessage.setText("下拉刷新");
if(isSuccess){
}else {
}
}
}
class MyScrollListner extends OnScrollListener{
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if(newState==RecyclerView.SCROLL_STATE_IDLE||newState==RecyclerView.SCROLL_STATE_DRAGGING){
if(getLastVisiblePosition()==mMyAdapeter.getItemCount()-1&&!isLoardingMore){
Log.e("AAAAAA","getLastVisiblePosition="+getLastVisiblePosition()+",getCount="+mMyAdapeter.getItemCount());
isLoardingMore=true;
footerView.setPadding(0,0,0,0);
if(mOnRefreshListner!=null){
mOnRefreshListner.onLoardingMore();
}
}
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
}
}
}
布局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.refreshrecylerview.widght.RefreshRecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.example.refreshrecylerview.widght.RefreshRecyclerView>
</RelativeLayout>
还有一个是动画集:
<?xml version="1.0" encoding="utf-8"?>
<animation-list
xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false"
>
<item android:drawable="@mipmap/loading_refresh1" android:duration="50"></item>
<item android:drawable="@mipmap/loading_refresh2" android:duration="50"></item>
<item android:drawable="@mipmap/loading_refresh3" android:duration="50"></item>
<item android:drawable="@mipmap/loading_refresh4" android:duration="50"></item>
<item android:drawable="@mipmap/loading_refresh5" android:duration="50"></item>
<item android:drawable="@mipmap/loading_refresh6" android:duration="50"></item>
<item android:drawable="@mipmap/loading_refresh7" android:duration="50"></item>
<item android:drawable="@mipmap/loading_refresh8" android:duration="50"></item>
<item android:drawable="@mipmap/loading_refresh9" android:duration="50"></item>
<item android:drawable="@mipmap/loading_refresh10" android:duration="50"></item>
<item android:drawable="@mipmap/loading_refresh11" android:duration="50"></item>
<item android:drawable="@mipmap/loading_refresh12" android:duration="50"></item>
<item android:drawable="@mipmap/loading_refresh13" android:duration="50"></item>
<item android:drawable="@mipmap/loading_refresh14" android:duration="50"></item>
<item android:drawable="@mipmap/loading_refresh15" android:duration="50"></item>
<item android:drawable="@mipmap/loading_refresh16" android:duration="50"></item>
</animation-list>
最后是使用:
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import com.example.refreshrecylerview.decoration.DividerItemDecoration;
import com.example.refreshrecylerview.widght.MyAdapeter;
import com.example.refreshrecylerview.widght.RefreshRecyclerView;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
private ArrayList<String> datas=new ArrayList<>();
private RefreshRecyclerView recyclerView;
private MyAdapeter myAdapeter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RefreshRecyclerView) this.findViewById(R.id.recyclerView);
//此处添加分割线
recyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL_LIST));
String str=new String();
for (int i = 0; i < 30; i++) {
str="我是第 "+i+" 个条目";
datas.add(str);
}
myAdapeter = new MyAdapeter(datas, this);
myAdapeter.addHeaderView(LayoutInflater.from(this).inflate(R.layout.refresh_listview_header,null));
myAdapeter.addFooterView(LayoutInflater.from(this).inflate(R.layout.refresh_listview_footer,null));
recyclerView.setAdapter(myAdapeter);
//下面这句代码一点要写,主要是考虑到头布局里可以加入一些其他布局,如ViewPager等
recyclerView.addSecondHeaderView(new View(this));
recyclerView.setOnRefreshListner(new RefreshRecyclerView.onRefreshListner() {
@Override
public void onPullDownRefresh() {
refreshData();
}
@Override
public void onLoardingMore() {
loardingData();
}
});
}
public void refreshData(){
new Thread(new Runnable() {
@Override
public void run() {
datas.clear();
String str;
for (int i = 0; i < 30; i++) {
str="我是第 "+i+" 个条目";
datas.add(str);
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
@Override
public void run() {
recyclerView.onRefreshfinish(true);
myAdapeter.notifyDataSetChanged();
}
});
}
}).start();
}
public void loardingData(){
new Thread(new Runnable() {
@Override
public void run() {
int size = datas.size();
String str;
for (int i = size; i < size+10; i++) {
str="我是第 "+i+" 个条目";
datas.add(str);
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
@Override
public void run() {
recyclerView.onRefreshfinish(true);
myAdapeter.notifyDataSetChanged();
}
});
}
}).start();
}
}
分割线:
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private static final int[] ATTRS = new int[]{
android.R.attr.listDivider
};
public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
private Drawable mDivider;
private int mOrientation;
public DividerItemDecoration(Context context, int orientation) {
final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
a.recycle();
setOrientation(orientation);
}
public void setOrientation(int orientation) {
if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
throw new IllegalArgumentException("invalid orientation");
}
mOrientation = orientation;
}
@Override
public void onDraw(Canvas c, RecyclerView parent) {
if (mOrientation == VERTICAL_LIST) {
drawVertical(c, parent);
} else {
drawHorizontal(c, parent);
}
}
public void drawVertical(Canvas c, RecyclerView parent) {
final int left = parent.getPaddingLeft();
final int right = parent.getWidth() - parent.getPaddingRight();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int top = child.getBottom() + params.bottomMargin +
Math.round(ViewCompat.getTranslationY(child));
final int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
public void drawHorizontal(Canvas c, RecyclerView parent) {
final int top = parent.getPaddingTop();
final int bottom = parent.getHeight() - parent.getPaddingBottom();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int left = child.getRight() + params.rightMargin +
Math.round(ViewCompat.getTranslationX(child));
final int right = left + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
@Override
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
if (mOrientation == VERTICAL_LIST) {
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
} else {
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
}
}
}