自从谷歌推出SwipeRefreshLayout之后越来越多的博客都是使用SwipeRefreshLayout来完成下拉刷新,但是往往产品经理根本不会使用谷歌的样式.每个公司都有一套自己的下拉样式这个时候就需要我们完全自定义RecyclerView的下拉刷新,基本查阅了网上所有的下拉刷新,但是效果都不怎么样.个人感觉我写的这个下拉刷新效果方面绝对的66666,欢迎可以提出一些改进意见:
废话不多说 先上效果图:
RecyclerView 出现以后,Android 里的下拉刷新和加载更多实现起来就非常容易了。当然,现成的库也有很多,只是总会有不一样的需求,而且我们往往只需要最基本的下拉刷新和加载更多功能,而不需要其他多余的功能。我只需要一个最纯粹的下拉刷新和加载更多。所以,自己动手显然是最好的结果了,也算是个小练习
在介绍代码之前我们先来讲一下实现原理:
首先,我们先通过重写RecyclerView的Adapter类装饰器为起实现addHeaderView,addFootView方法来添加头部与尾部。头部的实现是通过动态的修改的头部控件的高度,尾部的实现是通过动态修改它的BottomMargin,因为尾部的是默认显示的,使用Margin好实现,如果想实现下拉刷新和上拉加载功能,那么就必须有拉伸效果,所以就像上面的那样,Header是通过设置height,Footer是通过设置BottomMargin来模拟拉伸效果。那么回弹效果呢?仅仅通过设置高度或者是间隔是达不到模拟回弹效果的,因此,就需要用Scroller来实现模拟回弹效果。
本项目我把它分为主要的五部分HeaderAndFooterWrapper,PullRefreshRecyclerView,RecyclerViewFooter,RecyclerViewHeader,MessageRelativeLayout
下面我们分开来介绍。
HeaderAndFooterWrapper
这个类主要实现了RecyclerView的addHeaderView,addFootView方法,详细资料看参考弘洋大神的Android 优雅的为RecyclerView添加HeaderView和FooterView
以下是详细代码:
-
/**
-
* Created by on 2017/7/5.
-
* 公司:北京华星成汇文化发展有限公司
-
* 描述:
-
*/
-
public class HeaderAndFooterWrapper extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
-
private static final int BASE_ITEM_TYPE_HEADER = 100000;
-
private static final int BASE_ITEM_TYPE_FOOTER = 200000;
-
//头集合 尾结合
-
private SparseArrayCompat<View> mHeaderViews = new SparseArrayCompat<>();
-
private SparseArrayCompat<View> mFootViews = new SparseArrayCompat<>();
-
private RecyclerView.Adapter mInnerAdapter;
-
/**
-
* 把传进来的adapter赋值给成员变量
-
*
-
* @param adapter
-
*/
-
public HeaderAndFooterWrapper(RecyclerView.Adapter adapter) {
-
mInnerAdapter = adapter;
-
}
-
private boolean isHeaderViewPos(int position) {
-
return position < getHeadersCount();
-
}
-
private boolean isFooterViewPos(int position) {
-
return position >= getHeadersCount() + getRealItemCount();
-
}
-
/**
-
* 添加头部方法
-
*
-
* @param view
-
*/
-
public void addHeaderView(View view) {
-
mHeaderViews.put(mHeaderViews.size() + BASE_ITEM_TYPE_HEADER, view);
-
}
-
/**
-
* 添加尾部方法
-
*
-
* @param view
-
*/
-
public void addFootView(View view) {
-
mFootViews.put(mFootViews.size() + BASE_ITEM_TYPE_FOOTER, view);
-
}
-
/**
-
* 获取头部集合的大小
-
*
-
* @return
-
*/
-
public int getHeadersCount() {
-
return mHeaderViews.size();
-
}
-
/**
-
* 获取尾部集合的大小
-
*
-
* @return
-
*/
-
public int getFootersCount() {
-
return mFootViews.size();
-
}
-
/**
-
* 获取adapter的大小
-
*
-
* @return
-
*/
-
private int getRealItemCount() {
-
return mInnerAdapter.getItemCount();
-
}
-
@Override
-
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-
if (mHeaderViews.get(viewType) != null) {
-
// ViewHolder holder = ViewHolder.createViewHolder(parent.getContext(), mHeaderViews.get(viewType));
-
// return holder;
-
return new HeaderViewHolder(mHeaderViews.get(viewType));
-
} else if (mFootViews.get(viewType) != null) {
-
// ViewHolder holder = ViewHolder.createViewHolder(parent.getContext(), mFootViews.get(viewType));
-
// return holder;
-
return new FootViewHolder(mFootViews.get(viewType));
-
}
-
return mInnerAdapter.onCreateViewHolder(parent, viewType);
-
}
-
@Override
-
public int getItemViewType(int position) {
-
if (isHeaderViewPos(position)) {
-
return mHeaderViews.keyAt(position);
-
} else if (isFooterViewPos(position)) {
-
return mFootViews.keyAt(position - getHeadersCount() - getRealItemCount());
-
}
-
return mInnerAdapter.getItemViewType(position - getHeadersCount());
-
}
-
@Override
-
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
-
if (isHeaderViewPos(position)) {
-
return;
-
}
-
if (isFooterViewPos(position)) {
-
return;
-
}
-
mInnerAdapter.onBindViewHolder(holder, position - getHeadersCount());
-
}
-
@Override
-
public int getItemCount() {
-
return getHeadersCount() + getFootersCount() + getRealItemCount();
-
}
-
@Override
-
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
-
mInnerAdapter.onAttachedToRecyclerView(recyclerView);
-
/**
-
* 解决网格布局问题
-
*/
-
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
-
if (layoutManager instanceof GridLayoutManager) {
-
final GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
-
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
-
@Override
-
public int getSpanSize(int position) {
-
int viewType = getItemViewType(position);
-
if (mHeaderViews.get(viewType) != null) {
-
return gridLayoutManager.getSpanCount();
-
} else if (mFootViews.get(viewType) != null) {
-
return gridLayoutManager.getSpanCount();
-
} else {
-
return 1;
-
}
-
}
-
});
-
}
-
}
-
// /**
-
// * 解决 StaggeredGridLayoutManager样式的加头部问题,暂时没用
-
// * @param holder
-
// */
-
// @Override
-
// public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
-
// mInnerAdapter.onViewAttachedToWindow(holder);
-
// int position = holder.getLayoutPosition();
-
// if (isHeaderViewPos(position) || isFooterViewPos(position)) {
-
// ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
-
//
-
// if (lp != null && lp instanceof StaggeredGridLayoutManager.LayoutParams) {
-
//
-
// StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
-
//
-
// p.setFullSpan(true);
-
// }
-
// }
-
// }
-
private class HeaderViewHolder extends RecyclerView.ViewHolder {
-
HeaderViewHolder(View itemView) {
-
super(itemView);
-
}
-
}
-
private class FootViewHolder extends RecyclerView.ViewHolder {
-
FootViewHolder(View itemView) {
-
super(itemView);
-
}
-
}
-
}
RecyclerViewHeader
RecyclerViewHeader继承自LinearLayout用来实现下拉刷新时的界面展示,可以分为三种状态:正常、准备刷新、正在加载。在添加布局文件的时候,指定高度为0,这是为了隐藏header,setState()是设置header的状态,因为header需要根据不同的状态,完成控件隐藏、显示、改变文字等操作,这个方法主要是在PullRefreshRecyclerView里面调用。除此之外,还有setVisiableHeight()和getVisiableHeight(),这两个方法是为了设置和获取Header中根布局文件的高度属性,从而完成拉伸和收缩的效果
-
/**
-
* Created by 刘龙 on 2017/7/18.
-
* 公司:北京华星成汇文化发展有限公司
-
* 描述:
-
*/
-
public class RecyclerViewHeader extends LinearLayout {
-
/**
-
* 动画执行时间
-
*/
-
private final int ROTATE_ANIM_DURATION = 180;
-
public final static int STATE_NORMAL = 0;
-
public final static int STATE_READY = 1;
-
public final static int STATE_REFRESHING = 2;
-
/**
-
* 当前状态
-
*/
-
private int mState = STATE_NORMAL;
-
//获取到头布局
-
private LinearLayout mContainer;
-
//获取到控件
-
private ImageView mArrowImageView;
-
// private ProgressBar mProgressBar;
-
private TextView mHintTextView;
-
//初始化动画
-
// private RotateAnimation mRotateUpAnim;
-
// private Animation mRotateDownAnim;
-
private TextView mTitleTextView;
-
private RelativeLayout mRealityContent;
-
public RecyclerViewHeader(Context context) {
-
this(context, null);
-
}
-
public RecyclerViewHeader(Context context, @Nullable AttributeSet attrs) {
-
this(context, attrs, 0);
-
}
-
public RecyclerViewHeader(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
-
super(context, attrs, defStyleAttr);
-
init(context);
-
}
-
private void init(Context context) {
-
// 初始情况,设置下拉刷新view高度为0
-
LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, 0);
-
//获取下拉布局
-
mContainer = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.pullrefrefh_recyclerview_header, (ViewGroup) getParent(), true);
-
//添加到改容器
-
addView(mContainer, lp);
-
//显示位置下面
-
setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL);
-
//初始化控件
-
mRealityContent = (RelativeLayout) mContainer.findViewById(R.id.pullRefresh_reality_content);
-
mArrowImageView = (ImageView) mContainer.findViewById(R.id.pullRefresh_arrow);
-
mHintTextView = (TextView) mContainer.findViewById(R.id.pullRefresh_text);
-
// mProgressBar = (ProgressBar) findViewById(R.id.pullRefresh_progressbar);
-
mTitleTextView = (TextView) mContainer.findViewById(R.id.pullRefresh_title);
-
//初始化动画
-
// mRotateUpAnim = new RotateAnimation(0.0f, -180.0f,
-
// Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
-
// 0.5f);
-
// mRotateUpAnim.setDuration(ROTATE_ANIM_DURATION);
-
// mRotateUpAnim.setFillAfter(true);
-
// mRotateDownAnim = new RotateAnimation(-180.0f, 0.0f,
-
// Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
-
// 0.5f);
-
// mRotateDownAnim.setDuration(ROTATE_ANIM_DURATION);
-
// mRotateDownAnim.setFillAfter(true);
-
}
-
public void setState(int state) {
-
//如果状态相同 直接返回
-
if (mState == state) return;
-
//如果传进来的是刷新状态
-
if (state == STATE_REFRESHING) { // 正在加载显示圆圈进度
-
// mArrowImageView.clearAnimation();
-
// mArrowImageView.setVisibility(View.INVISIBLE);
-
// mProgressBar.setVisibility(View.VISIBLE);
-
} else { // 显示箭头图片
-
// mArrowImageView.setVisibility(View.VISIBLE);
-
// mProgressBar.setVisibility(View.INVISIBLE);
-
}
-
switch (state) {
-
case STATE_NORMAL://正常状态
-
if (mState == STATE_READY) {
-
// mArrowImageView.startAnimation(mRotateDownAnim);
-
}
-
if (mState == STATE_REFRESHING) {
-
// mArrowImageView.clearAnimation();
-
}
-
mHintTextView.setText("下拉刷新");
-
break;
-
case STATE_READY://可以刷新状态
-
if (mState != STATE_READY) {
-
// mArrowImageView.clearAnimation();
-
// mArrowImageView.startAnimation(mRotateUpAnim);
-
mHintTextView.setText("松开刷新数据");
-
}
-
break;
-
case STATE_REFRESHING://刷新状态
-
mHintTextView.setText("正在加载...");
-
break;
-
default:
-
}
-
mState = state;
-
}
-
/**
-
* 设置显示的图片
-
*
-
* @param imagePath
-
*/
-
public void setPullImage(String imagePath) {
-
Drawable fromPath = Drawable.createFromPath(imagePath);
-
Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
-
// mArrowImageView.setBackground(fromPath);
-
mArrowImageView.setImageBitmap(bitmap);
-
}
-
/**
-
* 设置显示的文字
-
*
-
* @param text
-
*/
-
public void setPullContent(String text) {
-
mTitleTextView.setText(text);
-
}
-
/**
-
* 获取本身实际的高度
-
*/
-
public int getRealityHeight() {
-
return mRealityContent.getHeight();
-
}
-
/**
-
* 设置隐藏高度
-
*
-
* @param height
-
*/
-
public void setVisibleHeight(int height) {
-
if (height < 0) {
-
height = 0;
-
}
-
LayoutParams lp = (LayoutParams) mContainer.getLayoutParams();
-
lp.height = height;
-
mContainer.setLayoutParams(lp);
-
}
-
/**
-
* 获取隐藏的高度
-
*
-
* @return
-
*/
-
public int getVisibleHeight() {
-
return mContainer.getLayoutParams().height;
-
}
-
}
说完了Header,我们再看看Footer。Footer是为了完成加载更多功能时候的界面展示,基本思路和Header是一样的,不过Footer的拉伸和显示效果不是通过高度来模拟的,而是通过设置BottomMargin来完成的。
-
/**
-
* Created by 刘龙 on 2017/8/9.
-
* 公司:北京华星成汇文化发展有限公司
-
* 描述:
-
*/
-
public class RecyclerViewFooter extends LinearLayout {
-
public final static int STATE_NORMAL = 0;
-
public final static int STATE_READY = 1;
-
public final static int STATE_LOADING = 2;
-
private Context context;
-
private View contentView;
-
private View progressBar;
-
private TextView hintView;
-
public RecyclerViewFooter(Context context) {
-
this(context, null);
-
}
-
public RecyclerViewFooter(Context context, @Nullable AttributeSet attrs) {
-
this(context, attrs, 0);
-
}
-
public RecyclerViewFooter(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
-
super(context, attrs, defStyleAttr);
-
this.context = context;
-
initView();
-
}
-
private void initView() {
-
LinearLayout moreView = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.pullrefrefh_recyclerview_footer, null);
-
addView(moreView);
-
moreView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
-
contentView = moreView.findViewById(R.id.pullrefrefh_footer_content);
-
progressBar = moreView.findViewById(R.id.pullrefrefh_footer_ProgressBar);
-
hintView = (TextView) moreView.findViewById(R.id.pullrefrefh_footer_hint_TextView);
-
}
-
/**
-
* 设置状态
-
*
-
* @param state
-
*/
-
public void setState(int state) {
-
hintView.setVisibility(View.INVISIBLE);
-
progressBar.setVisibility(View.INVISIBLE);
-
hintView.setVisibility(View.INVISIBLE);
-
if (state == STATE_READY) {
-
hintView.setVisibility(View.VISIBLE);
-
hintView.setText("松开载入更多");
-
} else if (state == STATE_LOADING) {
-
progressBar.setVisibility(View.VISIBLE);
-
} else {
-
hintView.setVisibility(View.VISIBLE);
-
hintView.setText("查看更多");
-
}
-
}
-
/**
-
* 设置距离下边的BottomMargin
-
*
-
* @param height
-
*/
-
public void setBottomMargin(int height) {
-
if (height < 0) return;
-
LayoutParams lp = (LayoutParams) contentView.getLayoutParams();
-
lp.bottomMargin = height;
-
contentView.setLayoutParams(lp);
-
}
-
/**
-
* 获取BottomMargin
-
*
-
* @return
-
*/
-
public int getBottomMargin() {
-
LayoutParams lp = (LayoutParams) contentView.getLayoutParams();
-
return lp.bottomMargin;
-
}
-
/**
-
* hide footer when disable pull load more
-
*/
-
public void hide() {
-
LayoutParams lp = (LayoutParams) contentView.getLayoutParams();
-
lp.height = 0;
-
contentView.setLayoutParams(lp);
-
}
-
/**
-
* show footer
-
*/
-
public void show() {
-
LayoutParams lp = (LayoutParams) contentView.getLayoutParams();
-
lp.height = LayoutParams.WRAP_CONTENT;
-
contentView.setLayoutParams(lp);
-
}
-
}
MessageRelativeLayout
该类主要是为了实现在刷新完毕的时候可以显示一个更新了多少条,网络错误等等的提示语:在添加布局文件的时候,指定高度为0,这是为了隐藏提示语,实现思路与头布局类似,如不需要此功能可忽略,不会影响代码的使用
-
/**
-
* Created by on 2017/7/18.
-
* 公司:北京华星成汇文化发展有限公司
-
* 描述:
-
*/
-
public class MessageRelativeLayout extends RelativeLayout {
-
//显示消息的控件
-
private LinearLayout mHeaderMessageView;
-
private TextView mHeaderMessageText;
-
private int mHeaderMessageViewHeight;
-
//滚动类
-
private Scroller mScroller;
-
public MessageRelativeLayout(Context context) {
-
this(context, null);
-
}
-
public MessageRelativeLayout(Context context, AttributeSet attrs) {
-
this(context, attrs, 0);
-
}
-
public MessageRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
-
super(context, attrs, defStyleAttr);
-
init(context);
-
}
-
private void init(Context context) {
-
//滚动类
-
mScroller = new Scroller(context, new DecelerateInterpolator());
-
//初始化一个显示消息的textView
-
mHeaderMessageView = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.pullrefresh_header_message, (ViewGroup) getParent(), false);
-
mHeaderMessageView.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0));
-
mHeaderMessageText = (TextView) mHeaderMessageView.findViewById(R.id.pullRefresh_message);
-
// 初始化 头部高度
-
mHeaderMessageText.getViewTreeObserver().addOnGlobalLayoutListener(
-
new ViewTreeObserver.OnGlobalLayoutListener() {
-
@Override
-
public void onGlobalLayout() {
-
mHeaderMessageViewHeight = mHeaderMessageText.getHeight();//57
-
getViewTreeObserver().removeOnGlobalLayoutListener(this);
-
}
-
});
-
}
-
@Override
-
protected void onFinishInflate() {
-
super.onFinishInflate();
-
//确保添加到后面
-
addView(mHeaderMessageView, 1);
-
}
-
public void showMessage() {
-
mScroller.startScroll(0, getHeaderMessageViewHeight(), 0, 0, PullRefreshRecyclerView.SCROLL_DURATION);
-
invalidate();
-
}
-
public void hideMessage() {
-
mScroller.startScroll(0, getVisibleHeight(), 0, -getVisibleHeight(), PullRefreshRecyclerView.SCROLL_DURATION);
-
invalidate();
-
}
-
/**
-
* 设置消息
-
*/
-
public void setMessage(String message) {
-
mHeaderMessageText.setText(message);
-
}
-
/**
-
* 获取消息总高度
-
*
-
* @return
-
*/
-
public int getHeaderMessageViewHeight() {
-
return mHeaderMessageViewHeight;
-
}
-
/**
-
* 设置隐藏高度
-
*
-
* @param height
-
*/
-
private void setVisibleHeight(int height) {
-
if (height < 0) {
-
height = 0;
-
}
-
LayoutParams lp = (LayoutParams) mHeaderMessageView.getLayoutParams();
-
lp.height = height;
-
mHeaderMessageView.setLayoutParams(lp);
-
}
-
/**
-
* 获取隐藏的高度
-
*
-
* @return
-
*/
-
public int getVisibleHeight() {
-
return mHeaderMessageView.getLayoutParams().height;
-
}
-
@Override
-
public void computeScroll() {
-
if (mScroller.computeScrollOffset()) {
-
setVisibleHeight(mScroller.getCurrY());
-
postInvalidate();
-
}
-
super.computeScroll();
-
}
-
}
PullRefreshRecyclerView
在了解了Header,Footer和Message之后,我们就要介绍最核心的PullRefreshRecyclerView的代码实现了。便于观看,本代码有部分删减重构
-
/**
-
* Created by 刘龙 on 2017/7/18.
-
* 公司:北京华星成汇文化发展有限公司
-
* 描述:
-
*/
-
public class PullRefreshRecyclerView extends RecyclerView {
-
private float mLastY = -1; // save event y
-
/**
-
* 滚动需要的时间
-
*/
-
public final static int SCROLL_DURATION = 200;
-
/**
-
* 提示消息显示时间
-
*/
-
public final static int MESSAGE_SHOW_DURATION = 2000;
-
/**
-
* 阻尼效果
-
*/
-
private final static float OFFSET_RADIO = 1.5f;
-
/**
-
* 上拉加载的距离,默认50px
-
*/
-
private static final int PULL_LOAD_MORE_DELTA = 50;
-
/**
-
* 是否设置为自动加载更多,目前没实现
-
*/
-
private boolean mEnableAutoLoading = false;
-
/**
-
* 是否可以上拉 默认可以
-
*/
-
private boolean mEnablePullLoad = true;
-
/**
-
* 是否可以下拉 默认可以
-
*/
-
private boolean mEnablePullRefresh = true;
-
/**
-
* 是否正在加载
-
*/
-
private boolean mPullLoading = false;
-
/**
-
* 是否正在刷新
-
*/
-
private boolean mPullRefreshing = false;
-
/**
-
* 区分上拉和下拉
-
*/
-
private int mScrollBack;
-
private final static int SCROLLBACK_HEADER = 0;
-
private final static int SCROLLBACK_FOOTER = 1;
-
//滚动类
-
private Scroller mScroller;
-
//头布局控件
-
private RecyclerViewHeader mHeaderView;
-
//尾控件
-
private RecyclerViewFooter mFooterView;
-
//消息提示类
-
private MessageRelativeLayout mParent;
-
//adapter的装饰类
-
private HeaderAndFooterWrapper mHeaderAndFooterWrapper;
-
public PullRefreshRecyclerView(Context context) {
-
this(context, null);
-
}
-
public PullRefreshRecyclerView(Context context, @Nullable AttributeSet attrs) {
-
this(context, attrs, 0);
-
}
-
public PullRefreshRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
-
super(context, attrs, defStyle);
-
init(context);
-
}
-
private void init(Context context) {
-
//滚动类
-
mScroller = new Scroller(context, new DecelerateInterpolator());
-
//获取到头布局
-
mHeaderView = new RecyclerViewHeader(context);
-
mHeaderView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
-
//获取尾布局
-
mFooterView = new RecyclerViewFooter(context);
-
mFooterView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
-
}
-
private Adapter adapter;
-
@Override
-
public void setAdapter(Adapter adapter) {
-
this.adapter = adapter;
-
mHeaderAndFooterWrapper = new HeaderAndFooterWrapper(adapter);
-
super.setAdapter(mHeaderAndFooterWrapper);
-
//添加头,确保是第一个
-
mHeaderAndFooterWrapper.addHeaderView(mHeaderView);
-
//添加尾,确保是第最后一个
-
mHeaderAndFooterWrapper.addFootView(mFooterView);
-
//获取到它的父容器
-
if (getParent() instanceof MessageRelativeLayout) {
-
mParent = (MessageRelativeLayout) getParent();
-
}
-
}
-
@Override
-
public boolean onTouchEvent(MotionEvent e) {
-
if (mLastY == -1) {
-
mLastY = e.getRawY();
-
}
-
switch (e.getAction()) {
-
case MotionEvent.ACTION_DOWN:
-
//按下的时候记录值
-
mLastY = e.getRawY();
-
break;
-
case MotionEvent.ACTION_MOVE:
-
float moveY = e.getRawY();
-
//手指滑动的差值
-
float distanceY = moveY - mLastY;
-
mLastY = moveY;
-
//第一个条目完全显示 //头部高度大于0 deltaY大于0 向下移动
-
if ((((LinearLayoutManager) getLayoutManager()).findFirstCompletelyVisibleItemPosition() == 0 || ((LinearLayoutManager) getLayoutManager()).findFirstCompletelyVisibleItemPosition() == 1) && (mHeaderView.getVisibleHeight() > 0 || distanceY > 0)) {
-
// 更新头部高度
-
updateHeaderHeight(distanceY / OFFSET_RADIO);
-
} else if (isSlideToBottom() && (mFooterView.getBottomMargin() > 0 || distanceY < 0)) {
-
Log.e("PullRefreshRecyclerView","-------111------"+distanceY);
-
//已经到达底部,改变状态或者自动加载
-
updateFooterHeight(-distanceY / OFFSET_RADIO);
-
}else if (distanceY > 0){
-
updateFooterHeight(-distanceY / OFFSET_RADIO);
-
}
-
break;
-
default:
-
mLastY = -1; // 复位
-
if ((((LinearLayoutManager) getLayoutManager()).findFirstCompletelyVisibleItemPosition() == 0 || ((LinearLayoutManager) getLayoutManager()).findFirstCompletelyVisibleItemPosition() == 1)) {
-
// 松手的时候 高度大于 一定值 调用刷新
-
if (mEnablePullRefresh && mHeaderView.getVisibleHeight() > mHeaderView.getRealityHeight()) {
-
//变为刷新状态
-
mPullRefreshing = true;
-
mHeaderView.setState(RecyclerViewHeader.STATE_REFRESHING);
-
//回调事件
-
if (mOnRefreshListener != null) {
-
mOnRefreshListener.onRefresh();
-
}
-
}
-
resetHeaderHeight();
-
} else if (isSlideToBottom()) {
-
// invoke load more.
-
if (mEnablePullLoad && mFooterView.getBottomMargin() > PULL_LOAD_MORE_DELTA && !mPullLoading) {
-
mPullLoading = true;
-
mFooterView.setState(RecyclerViewFooter.STATE_LOADING);
-
if (mOnRefreshListener != null) {
-
mOnRefreshListener.onLoadMore();
-
}
-
}
-
resetFooterHeight();
-
} else {
-
// resetFooterHeight();
-
resetHeaderHeight();
-
}
-
break;
-
}
-
return super.onTouchEvent(e);
-
}
-
/**
-
* 更新尾部加载
-
*
-
* @param distance
-
*/
-
private void updateFooterHeight(float distance) {
-
int height = mFooterView.getBottomMargin() + (int) distance;
-
Log.e("PullRefreshRecyclerView","-------------"+height);
-
if (mEnablePullLoad && !mPullLoading) {
-
if (height > PULL_LOAD_MORE_DELTA) {
-
//改变状态
-
mFooterView.setState(RecyclerViewFooter.STATE_READY);
-
} else {
-
mFooterView.setState(RecyclerViewFooter.STATE_NORMAL);
-
}
-
}
-
mFooterView.setBottomMargin(height);
-
}
-
/**
-
* 更新头部刷新
-
*
-
* @param distance
-
*/
-
private void updateHeaderHeight(float distance) {
-
// 设置头部高度,原先的高度加上
-
mHeaderView.setVisibleHeight((int) distance + mHeaderView.getVisibleHeight());
-
// 未处于刷新状态,更新箭头
-
if (mEnablePullRefresh && !mPullRefreshing) {
-
//下拉高度到达可以刷新的位置
-
if (mHeaderView.getVisibleHeight() > mHeaderView.getRealityHeight()) {
-
mHeaderView.setState(RecyclerViewHeader.STATE_READY);
-
} else {
-
mHeaderView.setState(RecyclerViewHeader.STATE_NORMAL);
-
}
-
}
-
//移动到顶部
-
smoothScrollBy(0, 0);
-
}
-
/**
-
* 重置头部高度
-
*/
-
private void resetHeaderHeight() {
-
int height = mHeaderView.getVisibleHeight();
-
if (height == 0) // 如果=0 是不可见的 直接返回
-
return;
-
if (mPullRefreshing && height <= mHeaderView.getRealityHeight()) {
-
return;
-
}
-
int finalHeight = 0;
-
if (mPullRefreshing && height > mHeaderView.getRealityHeight()) {
-
finalHeight = mHeaderView.getRealityHeight();
-
}
-
if (mParent != null) {
-
if (mHeaderView.getVisibleHeight() == mParent.getHeaderMessageViewHeight()) {
-
finalHeight = mParent.getHeaderMessageViewHeight();
-
}
-
}
-
mScrollBack = SCROLLBACK_HEADER;//设置标识
-
mScroller.startScroll(0, height, 0, finalHeight - height, SCROLL_DURATION);
-
// 触发计算滚动
-
invalidate();
-
}
-
/**
-
* 重置尾部高度
-
*/
-
private void resetFooterHeight() {
-
int bottomMargin = mFooterView.getBottomMargin();
-
if (bottomMargin > 0) {
-
mScrollBack = SCROLLBACK_FOOTER;//设置标识
-
mScroller.startScroll(0, bottomMargin, 0, -bottomMargin, SCROLL_DURATION);
-
invalidate();
-
}
-
}
-
/**
-
* 停止刷新
-
*/
-
public void stopRefresh() {
-
mScrollBack = SCROLLBACK_HEADER;//设置标识
-
int obligateHeight;
-
if (mParent != null) {
-
obligateHeight = mParent.getHeaderMessageViewHeight();
-
} else {
-
obligateHeight = 0;
-
}
-
int height = mHeaderView.getVisibleHeight();
-
if (mPullRefreshing) {
-
//是否复位
-
mPullRefreshing = false;
-
//显示更新了多少条消息
-
if (mParent != null) {
-
mParent.showMessage();
-
}
-
mScroller.startScroll(0, height, 0, obligateHeight - height, SCROLL_DURATION);
-
// 触发计算滚动
-
invalidate();
-
//延时执行复位移动
-
if (mParent != null) {
-
handler.removeCallbacksAndMessages(null);
-
handler.sendEmptyMessageDelayed(1, MESSAGE_SHOW_DURATION);
-
}
-
}
-
}
-
/**
-
* 停止加载
-
*/
-
public void stopLoadMore() {
-
if (mPullLoading) {
-
mPullLoading = false;
-
mFooterView.setState(RecyclerViewFooter.STATE_NORMAL);
-
}
-
}
-
/**
-
* 消息
-
*/
-
private Handler handler = new Handler() {
-
@Override
-
public void handleMessage(Message msg) {
-
super.handleMessage(msg);
-
if (mHeaderView.getVisibleHeight() == mParent.getHeaderMessageViewHeight()) {
-
// resetHeaderHeight();
-
mScroller.startScroll(0, mHeaderView.getVisibleHeight(), 0, -mHeaderView.getVisibleHeight(), SCROLL_DURATION);
-
postInvalidate();
-
}
-
mParent.hideMessage();
-
}
-
};
-
@Override
-
public void computeScroll() {
-
if (mScroller.computeScrollOffset()) {
-
if (mScrollBack == SCROLLBACK_HEADER) {
-
mHeaderView.setVisibleHeight(mScroller.getCurrY());
-
} else {
-
mFooterView.setBottomMargin(mScroller.getCurrY());
-
}
-
postInvalidate();
-
}
-
super.computeScroll();
-
}
-
private OnRefreshListener mOnRefreshListener;
-
public void setOnRefreshListener(OnRefreshListener onRefreshListener) {
-
mOnRefreshListener = onRefreshListener;
-
}
-
/**
-
* 刷新接口,
-
*/
-
public interface OnRefreshListener {
-
void onRefresh();
-
void onLoadMore();
-
}
-
/**
-
* 判断是否到底
-
*
-
* @return
-
*/
-
private boolean isSlideToBottom() {
-
return computeVerticalScrollExtent() + computeVerticalScrollOffset() >= computeVerticalScrollRange();
-
}
-
}