PullRefreshRecyclerView.java
/**
* 类说明:下拉刷新上拉加载更多的RecyclerView
* Author: gaobaiq
* Date: 2016/5/9 18:09
*/
public class PullRefreshRecyclerView extends PullRefreshView { /**
* 内置的RecyclerView;
*/
private RecyclerView mRecyclerView; /**
* 可见的最后一个item
*/
private int lastVisibleItem; /**
* 可见的第一个item
*/
private int firstVisibleItem; /**
* 空数据提示布局容器
*/
private LinearLayout mEmptyLayout; /**
* 是否自动上拉刷新
*/
private boolean isAutomaticUp = false; public PullRefreshRecyclerView(Context context) {
this(context, null);
} public PullRefreshRecyclerView(Context context, AttributeSet attrs) {
this(context, attrs, );
} public PullRefreshRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mRecyclerView = new RecyclerView(context);
mRecyclerView.setClipToPadding(false);
this.addView(mRecyclerView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
initListener();
} private void initListener() {
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (isAutomaticUp && newState == RecyclerView.SCROLL_STATE_IDLE && pullUp()) {
triggerPullUpRefresh();
}
} @Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
getVisibleItem();
}
});
} private int getMax(int[] arr) {
int max = arr[];
for (int x = ; x < arr.length; x++) {
if (arr[x] > max)
max = arr[x];
}
return max;
} private int getMin(int[] arr) {
int min = arr[];
for (int x = ; x < arr.length; x++) {
if (arr[x] < min)
min = arr[x];
}
return min;
} @Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
getVisibleItem();
break;
}
return super.onTouchEvent(event);
} /**
* 获取当前第一个显示的item 和 最后一个显示的item.
*/
private void getVisibleItem() {
RecyclerView.LayoutManager layout = mRecyclerView.getLayoutManager(); if (layout != null) {
if (layout instanceof LinearLayoutManager) {
lastVisibleItem = ((LinearLayoutManager) layout).findLastVisibleItemPosition();
firstVisibleItem = ((LinearLayoutManager) layout).findFirstVisibleItemPosition();
} else if (layout instanceof GridLayoutManager) {
lastVisibleItem = ((GridLayoutManager) layout).findLastVisibleItemPosition();
firstVisibleItem = ((GridLayoutManager) layout).findFirstVisibleItemPosition();
} else if (layout instanceof StaggeredGridLayoutManager) {
int[] lastPositions = new int[((StaggeredGridLayoutManager) layout).getSpanCount()];
((StaggeredGridLayoutManager) layout).findLastVisibleItemPositions(lastPositions);
lastVisibleItem = getMax(lastPositions);
int[] firstPositions = new int[((StaggeredGridLayoutManager) layout).getSpanCount()];
((StaggeredGridLayoutManager) layout).findFirstVisibleItemPositions(firstPositions);
firstVisibleItem = getMin(lastPositions);
}
}
} @Override
protected boolean isChildBottom(ViewGroup viewGroup) { boolean resultValue = false;
int childNum = viewGroup.getChildCount(); if (childNum == || mRecyclerView.getChildCount() == ) {
resultValue = false;
} else { if (mRecyclerView.equals(getChildAt()) && lastVisibleItem != mRecyclerView.getAdapter().getItemCount() - ) {
return false;
} View view = viewGroup.getChildAt(childNum - );
int bottomMargin = ((MarginLayoutParams) view.getLayoutParams()).bottomMargin;
if (view.getBottom() + bottomMargin + viewGroup.getPaddingBottom() <= getHeight()) {
resultValue = true;
}
}
return resultValue;
} @Override
protected boolean isChildTop(ViewGroup viewGroup) {
boolean resultValue = false;
int childNum = viewGroup.getChildCount(); if (childNum == ) {
resultValue = true;
} else {
if (mRecyclerView.equals(getChildAt()) && firstVisibleItem != ) {
return false;
} View view = viewGroup.getChildAt();
int topMargin = ((MarginLayoutParams) view.getLayoutParams()).topMargin; if (view.getTop() - topMargin - viewGroup.getPaddingTop() >= ) {
resultValue = true;
}
}
return resultValue;
} @Override
public void triggerPullDownRefresh() {
mRecyclerView.scrollToPosition();
super.triggerPullDownRefresh();
} /**
* 设置空布局
*
* @param emptyView
* @param layoutGravity 空布局在父布局的方向
*/
public void setEmptyView(View emptyView, int layoutGravity) {
if (mEmptyLayout == null) {
initEmptyLayout();
}
mEmptyLayout.setGravity(layoutGravity);
mEmptyLayout.addView(emptyView);
} /**
* 显示空布局
*/
public void showEmptyView() {
if (mEmptyLayout != null && mEmptyLayout.getParent() == null) {
addView(mEmptyLayout, );
}
if (mRecyclerView.getParent() != null) {
removeView(mRecyclerView);
}
} /**
* 隐藏空布局
*/
public void hideEmptyView() {
if (mRecyclerView.getParent() == null) {
addView(mRecyclerView, );
}
if (mEmptyLayout != null && mEmptyLayout.getParent() != null) {
removeView(mEmptyLayout);
}
} private void initEmptyLayout() {
mEmptyLayout = new LinearLayout(mContext);
LayoutParams lp = new LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
mEmptyLayout.setLayoutParams(lp);
mEmptyLayout.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
} /**
* 滑动到底部时,是否自动触发上拉加载更多。
*
* @param isAutomaticUp
*/
public void isAutomaticUp(boolean isAutomaticUp) {
this.isAutomaticUp = isAutomaticUp;
} //提供获取内置RecyclerView的方法
public RecyclerView getRecyclerView() {
return mRecyclerView;
} //********* 提供一系列对内置RecyclerView的操作方法 *********// public void setLayoutManager(RecyclerView.LayoutManager layoutManager) {
mRecyclerView.setLayoutManager(layoutManager);
} public void setAdapter(RecyclerView.Adapter adapter) {
mRecyclerView.setAdapter(adapter);
} public void setItemAnimator(RecyclerView.ItemAnimator animator) {
mRecyclerView.setItemAnimator(animator);
} public void addItemDecoration(RecyclerView.ItemDecoration decor) {
mRecyclerView.addItemDecoration(decor);
} public void addItemDecoration(RecyclerView.ItemDecoration decor, int index) {
mRecyclerView.addItemDecoration(decor, index);
} public void setViewPadding(int left, int top, int right, int bottom) {
mRecyclerView.setPadding(left, top, right, bottom);
} }

PullRefreshView.java

/**
* 类说明: 自定义的上下拉刷新控件
* Author: gaobaiq
* Date: 2016/5/9 17:27
*/
public class PullRefreshView extends ViewGroup { private static final String TAG = PullRefreshView.class.getSimpleName(); protected Context mContext; //头部下拉的最小高度
private static final int HEAD_DEFAULT_HEIGHT = ; //尾部上拉的最小高度
private static final int TAIL_DEFAULT_HEIGHT = ; /**
* 头部容器
*/
private LinearLayout mHeadLayout; /**
* 头部View
*/
private View mHead; /**
* 头部的高度
*/
private int mHeadHeight = HEAD_DEFAULT_HEIGHT; /**
* 尾部容器
*/
private LinearLayout mTailLayout; /**
* 尾部View
*/
private View mTail; /**
* 尾部的高度
*/
private int mTailHeight = TAIL_DEFAULT_HEIGHT; /**
* 滑动的偏移量
*/
private int mScrollOffset = ; /**
* 标记 无状态(既不是上拉 也 不是下拉)
*/
private final int STATE_NOT = -; /**
* 标记 上拉状态
*/
private final int STATE_UP = ; /**
* 标记 下拉状态
*/
private final int STATE_DOWN = ; /**
* 当前状态
*/
private int mCurrentState = STATE_NOT; /**
* 是否处于下拉 正在更新状态
*/
private boolean mIsPullDown = false; /**
* 是否处于上拉 正在加载状态
*/
private boolean mIsPullUp = false; /**
* 是否启用下拉功能(默认不开启)
*/
private boolean mIsDownRefresh = true; /**
* 是否启用上拉功能(默认不开启)
*/
private boolean mIsUpRefresh = false; /**
* 加载状态
*/
private boolean mIsLoading = false; private int mDamp = ; /**
* 头部状态监听器
*/
private OnHeadStateListener mHeadStateListener; /**
* 尾部状态监听器
*/
private OnTailStateListener mTailStateListener; /**
* 上拉监听器
*/
private OnPullUpRefreshListener mPullUpRefreshListener; /**
* 下拉监听器
*/
private OnPullDownRefreshListener mPullDownRefreshListener; /**
* 是否还有更多数据。
*/
private boolean isMore = true; public PullRefreshView(Context context) {
this(context, null);
} public PullRefreshView(Context context, AttributeSet attrs) {
this(context, attrs, );
} public PullRefreshView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
setClipToPadding(false);
initHeadLayout();
initTailLayout();
} /**
* 初始化头部
*/
private void initHeadLayout() {
mHeadLayout = new LinearLayout(mContext);
LayoutParams lp = new LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
mHeadLayout.setGravity(Gravity.CENTER | Gravity.BOTTOM);
mHeadLayout.setLayoutParams(lp);
addView(mHeadLayout);
} /**
* 设置头部View
*
* @param head
*/
public void setHead(View head) {
mHead = head;
mHeadLayout.removeAllViews();
mHeadLayout.addView(mHead); //获取头部高度
mHeadLayout.post(new Runnable() {
@Override
public void run() {
if (mHead.getHeight() > HEAD_DEFAULT_HEIGHT) {
mHeadHeight = mHead.getHeight();
} else {
mHeadHeight = HEAD_DEFAULT_HEIGHT;
}
Log.e(TAG, "mHeadHeight" + mHeadHeight);
//当获取到头部高度的时候,如果正处于下拉刷新状态,应该把头部打开。
if (mIsPullDown) {
scroll(-mHeadHeight);
}
invalidate();
}
});
} /**
* 初始化尾部
*/
private void initTailLayout() {
mTailLayout = new LinearLayout(mContext);
LayoutParams lp = new LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
mTailLayout.setGravity(Gravity.CENTER | Gravity.BOTTOM);
mTailLayout.setLayoutParams(lp);
addView(mTailLayout);
} /**
* 设置尾部View
*
* @param tail
*/
public void setTail(View tail) {
mTail = tail;
mTailLayout.removeAllViews();
mTailLayout.addView(mTail); //获取尾部高度
mTailLayout.post(new Runnable() {
@Override
public void run() {
if (mTail.getHeight() > TAIL_DEFAULT_HEIGHT) {
mTailHeight = mTail.getHeight();
} else {
mTailHeight = TAIL_DEFAULT_HEIGHT;
}
Log.e(TAG, "mTailHeight" + mTailHeight);
//当获取到尾部高度的时候,如果正处于上拉刷新状态,应该把尾部打开。
if (mIsPullUp) {
scroll(mTailHeight);
}
}
});
invalidate();
} @Override
protected void onLayout(boolean changed, int l, int t, int r, int b) { //布局头部
View head = getChildAt();
head.layout(getPaddingLeft(), -mHeadHeight, getPaddingLeft() + head.getMeasuredWidth(), ); //布局尾部
View tail = getChildAt();
tail.layout(getPaddingLeft(), getMeasuredHeight(), getPaddingLeft() + tail.getMeasuredWidth(), getMeasuredHeight() + mTailHeight); //布局内容容器
int count = getChildCount();
if (count > ) {
View content = getChildAt();
content.layout(getPaddingLeft(), getPaddingTop(), getPaddingLeft() + content.getMeasuredWidth(), getPaddingTop() + content.getMeasuredHeight());
}
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec); //测量头部高度
View head = getChildAt();
measureChild(head, widthMeasureSpec, heightMeasureSpec); //测量尾部高度
View tail = getChildAt();
measureChild(tail, widthMeasureSpec, heightMeasureSpec); //测量内容容器宽高
int count = getChildCount();
int contentHeight = ;
int contentWidth = ;
if (count > ) {
View content = getChildAt();
measureChild(content, widthMeasureSpec, heightMeasureSpec);
contentHeight = content.getMeasuredHeight();
contentWidth = content.getMeasuredWidth();
} //设置PullRefresView的宽高
setMeasuredDimension(measureWidth(widthMeasureSpec, contentWidth), measureHeigth(heightMeasureSpec, contentHeight));
} private int measureWidth(int measureSpec, int contentWidth) {
int result = ;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec); if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else {
result = contentWidth + getPaddingLeft() + getPaddingRight();
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize);
}
} return result;
} private int measureHeigth(int measureSpec, int contentHeight) {
int result = ;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec); if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else {
result = contentHeight + getPaddingTop() + getPaddingBottom();
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize);
}
} return result;
} /**
* 设置是否启用上下拉功能
*
* @param isDownRefresh 是否开启下拉功能 默认开启
* @param isUpRefresh 是否开启上拉功能 默认不开启
*/
public void setRefresh(boolean isDownRefresh, boolean isUpRefresh) {
mIsDownRefresh = isDownRefresh;
mIsUpRefresh = isUpRefresh;
} /**
* 还原
*/
private void restore() {
mCurrentState = STATE_NOT;
scroll();
} /**
* 通知刷新完成
*/
public void refreshFinish() {
restore();
if (mIsLoading) {
mIsLoading = false;
if (mIsPullUp) {
mIsPullUp = false;
if (mTailStateListener != null && isMore) {
mTailStateListener.onRetractTail(mTail);
}
} else if (mIsPullDown) {
mIsPullDown = false;
if (mHeadStateListener != null) {
mHeadStateListener.onRetractHead(mHead);
}
}
}
} public void isMore(boolean isMore) {
this.isMore = isMore;
if (mTailStateListener != null) {
if (isMore) {
mTailStateListener.onHasMore(mTail);
} else {
mTailStateListener.onNotMore(mTail);
}
}
} /**
* 触发下拉刷新
*/
public void triggerPullDownRefresh() { if (!mIsDownRefresh) {
return;
} if (!mIsLoading) {
mIsLoading = true;
mIsPullDown = true;
mCurrentState = STATE_NOT;
scroll(-mHeadHeight);
if (mHeadStateListener != null) {
mHeadStateListener.onRefreshHead(mHead);
} if (mPullDownRefreshListener != null) {
mPullDownRefreshListener.onRefresh();
}
}
} /**
* 触发上拉刷新
*/
public void triggerPullUpRefresh() { if (!mIsUpRefresh) {
return;
} if (!mIsLoading) {
mIsLoading = true;
mIsPullUp = true;
mCurrentState = STATE_NOT;
scroll(mTailHeight);
if (mTailStateListener != null && isMore) {
mTailStateListener.onRefreshTail(mTail);
} if (isMore) {
if (mPullUpRefreshListener != null) {
mPullUpRefreshListener.onRefresh();
}
} else {
refreshFinish();
} }
} /**
* @param offset
*/
private void scroll(int offset) { if (offset < && !mIsDownRefresh) {
return;
} if (offset > && !mIsUpRefresh) {
return;
} scrollTo(, offset);
mScrollOffset = Math.abs(offset); if (mCurrentState == STATE_DOWN && mHeadStateListener != null) {
mHeadStateListener.onScrollChange(mHead, mScrollOffset, mScrollOffset >= mHeadHeight ? : mScrollOffset * / mHeadHeight);
} if (mCurrentState == STATE_UP && mTailStateListener != null && isMore) {
mTailStateListener.onScrollChange(mTail, mScrollOffset, mScrollOffset >= mTailHeight ? : mScrollOffset * / mTailHeight);
}
} /**
* 设置拉动阻力 (1到10)
*
* @param damp
*/
public void setDamp(int damp) {
if (damp < ) {
mDamp = ;
} else if (damp > ) {
mDamp = ;
} else {
mDamp = damp;
}
} @Override
public boolean onTouchEvent(MotionEvent event) { int y = (int) event.getY(); switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
return true;
case MotionEvent.ACTION_MOVE:
if (mY > y) {
if (mCurrentState == STATE_UP) {
scroll((mY - y) / mDamp);
}
} else if (mCurrentState == STATE_DOWN) {
scroll((mY - y) / mDamp);
}
break;
case MotionEvent.ACTION_UP:
if (!mIsPullDown && !mIsPullUp) {
if (mCurrentState == STATE_DOWN) {
if (mScrollOffset < mHeadHeight) {
restore();
} else {
triggerPullDownRefresh();
}
} else if (mCurrentState == STATE_UP) {
if (mScrollOffset < mTailHeight) {
restore();
} else {
triggerPullUpRefresh();
}
} else {
restore();
}
}
mY = ; break;
default: break;
}
return super.onTouchEvent(event);
} int mY = ; @Override
public boolean onInterceptTouchEvent(MotionEvent ev) { int y = (int) ev.getY(); switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mY = (int) ev.getY();
return false;
case MotionEvent.ACTION_MOVE:
if (mIsLoading) {
return false;
} if (pullDown() && y - mY > ) {
mCurrentState = STATE_DOWN;
return true;
} if (pullUp() && mY - y > ) {
mCurrentState = STATE_UP;
return true;
} return false;
case MotionEvent.ACTION_UP: return false;
} return false;
} protected boolean pullDown() {
return mCurrentState != STATE_UP && mIsDownRefresh && isTop();
} protected boolean pullUp() {
return mCurrentState != STATE_DOWN && mIsUpRefresh && isBottom();
} protected boolean isTop() { if (getChildCount() < ) {
return true;
} View view = getChildAt(); if (view instanceof ViewGroup) { if (view instanceof ScrollView) {
ScrollView scrollView = (ScrollView) view;
return scrollView.getScrollY() <= ;
} else {
return isChildTop((ViewGroup) view);
}
} else {
return true;
}
} protected boolean isChildTop(ViewGroup viewGroup) {
int minY = ;
int count = viewGroup.getChildCount();
for (int i = ; i < count; i++) {
View view = viewGroup.getChildAt(i);
int topMargin = ;
LayoutParams lp = view.getLayoutParams();
if (lp instanceof MarginLayoutParams) {
topMargin = ((MarginLayoutParams) lp).topMargin;
}
int top = view.getTop() - topMargin;
minY = Math.min(minY, top);
}
return minY >= ;
} protected boolean isBottom() { if (getChildCount() < ) {
return false;
} View view = getChildAt(); if (view instanceof ViewGroup) {
if (view instanceof ScrollView) {
ScrollView scrollView = (ScrollView) view;
if (scrollView.getChildCount() > ) {
return scrollView.getScrollY() >= scrollView.getChildAt().getHeight() - scrollView.getHeight();
} else {
return true;
}
} else {
return isChildBottom((ViewGroup) view);
}
} else {
return true;
}
} protected boolean isChildBottom(ViewGroup viewGroup) {
int maxY = ;
int count = viewGroup.getChildCount(); if (count == ) {
return false;
} for (int i = ; i < count; i++) {
View view = viewGroup.getChildAt(i);
int bottomMargin = ;
LayoutParams lp = view.getLayoutParams();
if (lp instanceof MarginLayoutParams) {
bottomMargin = ((MarginLayoutParams) lp).bottomMargin;
}
int bottom = view.getBottom() + bottomMargin;
maxY = Math.max(maxY, bottom);
} int h = viewGroup.getMeasuredHeight() - viewGroup.getPaddingBottom(); return maxY <= h;
} /**
* 设置头部监听器
*
* @param listener
*/
public void setOnHeadStateListener(OnHeadStateListener listener) {
mHeadStateListener = listener;
} /**
* 设置尾部监听器
*
* @param listener
*/
public void setOnTailStateListener(OnTailStateListener listener) {
mTailStateListener = listener;
} /**
* 设置上拉监听器
*
* @param listener
*/
public void setOnPullUpRefreshListener(OnPullUpRefreshListener listener) {
mPullUpRefreshListener = listener;
} /**
* 设置下拉监听器
*
* @param listener
*/
public void setOnPullDownRefreshListener(OnPullDownRefreshListener listener) {
mPullDownRefreshListener = listener;
} /**
* 移除头部监听器
*/
public void removeOnHeadStateListener() {
mHeadStateListener = null;
} /**
* 移除尾部监听器
*/
public void removeOnTailStateListener() {
mTailStateListener = null;
} /**
* 移除上拉监听器
*/
public void removeOnPullUpRefreshListener() {
mPullUpRefreshListener = null;
} /**
* 移除下拉监听器
*/
public void removeOnPullDownRefreshListener() {
mPullDownRefreshListener = null;
} //---------------- 监听接口 -------------------// /**
* 头部状态监听器
*/
public interface OnHeadStateListener { /**
* 头部滑动变化
*
* @param head 头部View
* @param scrollOffset 滑动距离
* @param scrollRatio 从开始到触发阀值的滑动比率(0到100)如果滑动到达了阀值,就算在滑动,这个值也是100
*/
void onScrollChange(View head, int scrollOffset, int scrollRatio); /**
* 头部处于刷新状态 (触发下拉刷新的时候调用)
*
* @param head 头部View
*/
void onRefreshHead(View head); /**
* 头部收起
*
* @param head 头部View
*/
void onRetractHead(View head); } /**
* 头部状态监听器
*/
public interface OnTailStateListener { /**
* 尾部滑动变化
*
* @param tail 尾部View
* @param scrollOffset 滑动距离
* @param scrollRatio 从开始到触发阀值的滑动比率(0到100)如果滑动到达了阀值,就算在滑动,这个值也是100
*/
void onScrollChange(View tail, int scrollOffset, int scrollRatio); /**
* 尾部处于加载状态 (触发上拉加载的时候调用)
*
* @param tail 尾部View
*/
void onRefreshTail(View tail); /**
* 尾部收起
*
* @param tail 尾部View
*/
void onRetractTail(View tail); /**
* 没有更多
*
* @param tail
*/
void onNotMore(View tail); /**
* 有更多
*
* @param tail
*/
void onHasMore(View tail);
} /**
* 上拉加载监听器
*/
public interface OnPullUpRefreshListener {
void onRefresh();
} /**
* 下拉更新监听器
*/
public interface OnPullDownRefreshListener {
void onRefresh();
}
}

HeadView.java

/**
* 类说明: 下拉刷新头部View
* Author: gaobaiq
* Date: 2016/5/9 19:07
*/
public class HeadView extends LinearLayout implements PullRefreshView.OnHeadStateListener { ImageView ivHeaderDownArrow;
ImageView ivHeaderLoading;
TextView textView; AnimationDrawable animationDrawable; private boolean isReach = false; public HeadView(Context context) {
super(context);
animationDrawable = (AnimationDrawable) getResources().getDrawable(R.drawable.progress_round);
init(context);
} private void init(Context context) {
LayoutInflater inflater = LayoutInflater.from(context);
View layout = inflater.inflate(R.layout.head_view_layout, this, false);
this.addView(layout, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
initView(layout);
restore();
this.setPadding(, , , );
} private void initView(View view){
ivHeaderDownArrow = (ImageView)view.findViewById(R.id.iv_header_down_arrow);
ivHeaderLoading = (ImageView)view.findViewById(R.id.iv_header_loading);
textView = (TextView)view.findViewById(R.id.tv_header_state);
} @Override
public void onScrollChange(View head, int scrollOffset, int scrollRatio) { if (scrollRatio == && !isReach) {
textView.setText("松开刷新");
ivHeaderDownArrow.setRotation();
isReach = true;
} else if (scrollRatio != && isReach) {
textView.setText("下拉刷新");
ivHeaderDownArrow.setRotation();
isReach = false;
}
} @Override
public void onRefreshHead(View head) {
ivHeaderLoading.setVisibility(VISIBLE);
ivHeaderDownArrow.setVisibility(GONE);
ivHeaderLoading.setImageDrawable(animationDrawable);
animationDrawable.start();
textView.setText("正在刷新");
} @Override
public void onRetractHead(View head) {
restore();
animationDrawable.stop();
isReach = false;
} private void restore() {
ivHeaderLoading.setVisibility(GONE);
ivHeaderDownArrow.setVisibility(VISIBLE);
ivHeaderLoading.setImageResource(R.drawable.loading1);
ivHeaderDownArrow.setImageResource(R.drawable.icon_down_arrow);
ivHeaderDownArrow.setRotation();
textView.setText("下拉刷新");
}
}

TailView.java

/**
* 类说明: 尾部上拉加载更多
* Author: gaobaiq
* Date: 2016/4/18 10:12
*/
public class TailView extends LinearLayout implements PullRefreshView.OnTailStateListener { ImageView ivHeaderDownArrow;
ImageView ivHeaderLoading;
TextView textView; AnimationDrawable animationDrawable; private boolean isReach = false;
private boolean isMore = true; public TailView(Context context) {
super(context);
animationDrawable = (AnimationDrawable) getResources().getDrawable(R.drawable.progress_round);
init(context);
} private void init(Context context) {
LayoutInflater inflater = LayoutInflater.from(context);
View layout = inflater.inflate(R.layout.head_view_layout, this, false);
this.addView(layout, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
initView(layout);
restore();
this.setPadding(, , , );
} private void initView(View view){
ivHeaderDownArrow = (ImageView)view.findViewById(R.id.iv_header_down_arrow);
ivHeaderLoading = (ImageView)view.findViewById(R.id.iv_header_loading);
textView = (TextView)view.findViewById(R.id.tv_header_state);
} @Override
public void onScrollChange(View tail, int scrollOffset, int scrollRatio) {
if (isMore) {
if (scrollRatio == && !isReach) {
textView.setText("松开加载");
ivHeaderDownArrow.setRotation();
isReach = true;
} else if (scrollRatio != && isReach) {
textView.setText("上拉加载");
isReach = false;
ivHeaderDownArrow.setRotation();
}
}
} @Override
public void onRefreshTail(View tail) {
if (isMore) {
ivHeaderLoading.setVisibility(VISIBLE);
ivHeaderDownArrow.setVisibility(GONE);
ivHeaderLoading.setImageDrawable(animationDrawable);
// AnimationDrawable animationDrawable = (AnimationDrawable) head.getBackground();
animationDrawable.start();
textView.setText("正在加载");
}
} @Override
public void onRetractTail(View tail) {
// animationDrawable = (AnimationDrawable) head.getBackground();
if (isMore) {
restore();
animationDrawable.stop();
isReach = false;
}
} @Override
public void onNotMore(View tail) {
ivHeaderLoading.setVisibility(GONE);
ivHeaderDownArrow.setVisibility(GONE);
textView.setText("已经全部加载完毕");
isMore = false;
} @Override
public void onHasMore(View tail) {
ivHeaderLoading.setVisibility(GONE);
ivHeaderDownArrow.setVisibility(VISIBLE);
textView.setText("上拉加载");
isMore = true;
} private void restore() {
ivHeaderLoading.setVisibility(GONE);
ivHeaderDownArrow.setVisibility(VISIBLE);
ivHeaderLoading.setImageResource(R.drawable.loading1);
ivHeaderDownArrow.setImageResource(R.drawable.icon_down_arrow);
ivHeaderDownArrow.setRotation();
textView.setText("上拉加载");
}
}

PullRefreshUtil.java

/**
* 类说明:
* Author: gaobaiq
* Date: 2016/5/9 20:04
*/
public class PullRefreshUtil { /**
* 刷新控件的基本配件 (头部、尾部都用默认的)
*
* @param view 刷新控件
* @param isDownRefresh 是否开启下拉刷新
* @param isUpRefresh 是否开启上拉加载
*/
public static void setRefresh(PullRefreshView view, boolean isDownRefresh, boolean isUpRefresh) { HeadView headView = null;
TailView tailView = null;
if (isDownRefresh) {
headView = new HeadView(view.getContext());
} if (isUpRefresh) {
tailView = new TailView(view.getContext());
} setRefresh(view, isDownRefresh, isUpRefresh, headView, tailView, headView, tailView);
} /**
* 刷新控件的基本配件 (自定义头部、尾部用默认的)
*
* @param view 刷新控件
* @param isDownRefresh 是否开启下拉刷新
* @param isUpRefresh 是否开启上拉加载
* @param headView 头部View
* @param headStateListener 头部监听器
*/
public static void setRefresh(PullRefreshView view, boolean isDownRefresh, boolean isUpRefresh, View headView, PullRefreshView.OnHeadStateListener headStateListener) { TailView tailView = null;
if (isUpRefresh) {
tailView = new TailView(view.getContext());
}
setRefresh(view, isDownRefresh, isUpRefresh, headView, tailView, headStateListener, tailView);
} /**
* 刷新控件的基本配件 (自定义尾部 、头部用默认的)
*
* @param view 刷新控件
* @param isDownRefresh 是否开启下拉刷新
* @param isUpRefresh 是否开启上拉加载
* @param tailView 尾部View
* @param tailStateListener 尾部监听器
*/
public static void setRefresh(PullRefreshView view, boolean isDownRefresh, boolean isUpRefresh, View tailView, PullRefreshView.OnTailStateListener tailStateListener) { HeadView headView = null;
if (isDownRefresh) {
headView = new HeadView(view.getContext());
}
setRefresh(view, isDownRefresh, isUpRefresh, headView, tailView, headView, tailStateListener);
} /**
* 刷新控件的基本配件 (自定义头部、尾部)
*
* @param view 刷新控件
* @param isDownRefresh 是否开启下拉刷新
* @param isUpRefresh 是否开启上拉加载
* @param headView 头部View
* @param tailView 尾部View
* @param headStateListener 头部监听器
* @param tailStateListener 尾部监听器
*/
public static void setRefresh(PullRefreshView view, boolean isDownRefresh, boolean isUpRefresh, View headView, View tailView, PullRefreshView.OnHeadStateListener headStateListener, PullRefreshView.OnTailStateListener tailStateListener) { view.setRefresh(isDownRefresh, isUpRefresh); if (isDownRefresh) {
view.setHead(headView);
view.setOnHeadStateListener(headStateListener);
} if (isUpRefresh) {
view.setTail(tailView);
view.setOnTailStateListener(tailStateListener);
}
}
}

progress_round.xml

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item
android:drawable="@drawable/loading1"
android:duration="" />
<item
android:drawable="@drawable/loading2"
android:duration="" />
<item
android:drawable="@drawable/loading3"
android:duration="" />
<item
android:drawable="@drawable/loading4"
android:duration="" />
<item
android:drawable="@drawable/loading5"
android:duration="" />
<item
android:drawable="@drawable/loading6"
android:duration="" />
<item
android:drawable="@drawable/loading7"
android:duration="" />
<item
android:drawable="@drawable/loading8"
android:duration="" />
<item
android:drawable="@drawable/loading9"
android:duration="" />
<item
android:drawable="@drawable/loading10"
android:duration="" />
<item
android:drawable="@drawable/loading11"
android:duration="" />
<item
android:drawable="@drawable/loading12"
android:duration="" />
</animation-list>

head_view_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="5dp"
android:gravity="center"> <ImageView
android:id="@+id/iv_header_down_arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/icon_down_arrow" /> <ImageView
android:id="@+id/iv_header_loading"
android:layout_width="25dp"
android:layout_height="25dp"
android:src="@drawable/progress_round"/> <TextView
android:id="@+id/tv_header_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:textSize="13sp"
android:textColor="#979797"
android:text="Loading" /> </LinearLayout>

   调用:

<com.app.gaobaiq.pullrefresh.PullRefreshRecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"/> PullRefreshUtil.setRefresh(mList, true, true);
mList.setOnPullDownRefreshListener(new PullRefreshView.OnPullDownRefreshListener() {
@Override public void onRefresh() {
mList.isMore(true); pageNum = ; loadData(); } });
mList.setOnPullUpRefreshListener( new PullRefreshView.OnPullUpRefreshListener() { @Override public void onRefresh() { pageNum++; loadData(); } }); // 加载完成 if (mList!= null) { mList.refreshFinish(); }
<com.app.gaobaiq.pullrefresh.PullRefreshView
android:id="@+id/refresh_view"
android:layout_width="match_parent"
android:layout_height="match_parent"> <ScrollView
android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"> </LinearLayout> </ScrollView> </com.app.gaobaiq.pullrefresh.PullRefreshView> PullRefreshUtil.setRefresh(mRefreshView, true, true);
mRefreshView.setOnPullDownRefreshListener(
new PullRefreshView.OnPullDownRefreshListener() {
@Override public void onRefresh() {
pageNum = ;
mRefreshView.isMore(true);
loadData();
}
});
mRefreshView.setOnPullUpRefreshListener(
new PullRefreshView.OnPullUpRefreshListener() {
@Override public void onRefresh() {
pageNum++;
loadData();
}
}); // 加载完成
if (mRefreshView != null) {
mRefreshView.refreshFinish();
}

Android 实现下拉刷新和上拉加载更多的RECYCLERVIEW和SCROLLVIEW的更多相关文章

  1. juery下拉刷新,div加载更多元素并添加点击事件(二)

    buffer.append("<div class='col-xs-3 "+companyId+"' style='padding-left: 10px; padd ...

  2. android--------自定义控件ListView实现下拉刷新和上拉加载

    开发项目过程中基本都会用到listView的下拉刷新和上滑加载更多,为了方便重写的ListView来实现下拉刷新,同时添加了上拉自动加载更多的功能. Android下拉刷新可以分为两种情况: 1.获取 ...

  3. Android 自定义 ListView 上下拉动“刷新最新”和“加载更多”歌曲列表

    本文内容 环境 测试数据 项目结构 演示 参考资料 本文演示,上拉刷新最新的歌曲列表,和下拉加载更多的歌曲列表.所谓"刷新最新"和"加载更多"是指日期.演示代码 ...

  4. Android 5.X新特性之为RecyclerView添加下拉刷新和上拉加载及SwipeRefreshLayout实现原理

    RecyclerView已经写过两篇文章了,分别是Android 5.X新特性之RecyclerView基本解析及无限复用 和 Android 5.X新特性之为RecyclerView添加Header ...

  5. Android 使用PullToRefresh实现下拉刷新和上拉加载(ExpandableListView)

    PullToRefresh是一套实现非常好的下拉刷新库,它支持: 1.ListView 2.ExpandableListView 3.GridView 4.WebView 等多种常用的需要刷新的Vie ...

  6. 使用PullToRefresh实现下拉刷新和上拉加载

    使用PullToRefresh实现下拉刷新和上拉加载 分类: Android2013-12-20 15:51 78158人阅读 评论(91) 收藏 举报 Android下拉刷新上拉加载PullToRe ...

  7. 安卓开发笔记——关于开源组件PullToRefresh实现下拉刷新和上拉加载(一分钟搞定,超级简单)

    前言 以前在实现ListView下拉刷新和上拉加载数据的时候都是去继承原生的ListView重写它的一些方法,实现起来非常繁杂,需要我们自己去给ListView定制下拉刷新和上拉加载的布局文件,然后添 ...

  8. 实现RecyclerView下拉刷新和上拉加载更多以及RecyclerView线性、网格、瀑布流效果演示

    实现RecyclerView下拉刷新和上拉加载更多以及RecyclerView线性.网格.瀑布流效果演示 效果预览 实例APP 小米应用商店 使用方法 build.gradle文件 dependenc ...

  9. Diycode开源项目 搭建可以具有下拉刷新和上拉加载的Fragment

    1.效果预览 1.1.这个首页就是一个Fragment碎片,本文讲述的就是这个碎片的搭建方式. 下拉会有一个旋转的刷新圈,上拉会刷新数据. 1.2.整体结构 首先底层的是BaseFragment 然后 ...

随机推荐

  1. php基础知识(一)--2017-04-14

    1.Php的两种打开方式: 第一种方式:地址栏打开:http://localhost/0414/qq.php     地址栏输入localhost/  就是phpstudy下的www文件夹 第二种:新 ...

  2. asp.net 后台给前台控件添加及设置属性

    txtTopImgBox.Attributes.Add("title", "12312121"); Text1.Style["background-c ...

  3. Asp.Net Core部署到Linux服务器

    从2016年7月, .NET Core1.0 正式发布开始,由于时间问题,我没怎么关注过.NET Core,最近刚抽出点时间研究了下,先讲下如何把ASP.NET Core部署到Linux上吧.这里我用 ...

  4. Asp.net Web Api中使用配置Unity

    第一步:建立web api,添加unity.webapi. 第二步:在添加了该引用之后,在App_Start中会自动生成UnityConfig.cs文件 第三步:添加数据做测试 第四步:展示效果

  5. (转)Django学习之 第四章:Django模板系统

    前面的章节我们看到如何在视图中返回HTML,但是HTML是硬编码在Python代码中的 这会导致几个问题: 1.显然,任何页面的改动会牵扯到Python代码的改动 网站的设计改动会比Python代码改 ...

  6. Android DrawerLayout设置左右侧滑菜单为全屏

    我们可以在MainActivity中获取屏幕宽度后动态赋值给侧滑菜单. 在oncreate时 DisplayMetrics metric = new DisplayMetrics(); getWind ...

  7. CommandType.Text

    CommandType.Text代表执行的是SQL语句CommandType.StoreProcedure代表执行的是存储过程CommandType代表要执行的类型 //返回DataTable的SQL ...

  8. 速学JavaScript!

    什么是JavaScript? JavaScript是一种轻量级的脚本语言,也是一种嵌入式语言,是一种对象模型语言,简称JS:JavaScript的核心语法部分(语言本身)很精简,只包括两个部分: 基本 ...

  9. 全文检索lucene6.1的检索方式

    背景: 工作任务完成后,闲暇之计给自己充充电! Lucene是一个纯java全文检索工具包,采用倒排索引原理. 全文检索:指的是计算机索引程序通过扫描文章的每一个词,对每一个词建立一个索引,并指明该词 ...

  10. EM_LGH CF965D Single-use Stones 思维_推理

    Code: #include<cstdio> #include<algorithm> using namespace std; const int maxn = 1000000 ...