您的位置:首页 > 其它

PullToReFresh 实现 RecycleView 横向滑动的刷新和加载更多

2016-08-09 18:10 645 查看
项目地址:https://github.com/moscoper/PullToRefresh.git

前言

一般的刷新和加载更多的效果都是竖直方向的(下拉刷新和上拉加载更多),本篇文章就利用 PullToReFresh 和 RecycleView 来实现水平方向的刷新和加载更多的效果。我们暂且叫它 PullToReshHorizontalRecycleView。

PullToReshHorizontalRecycleView

我们在 PullToRefresh 的扩展 这篇文章中介绍过如何利用 PullToReFresh 对其他可以滑动的控件添加下拉和上拉的效果。PullToReshHorizontalRecycleView 的实现和其类似。

继承 PullToRefreshBase

新建类
PullToReshHorizontalRecycleView
继承
PullToRefreshBase<RecyclerView>
。并实现
getPullToRefreshScrollDirection
createRefreshableView
,
isReadyForPullStart
isReadyForPullEnd
这四个方法。

getPullToRefreshScrollDirection

方法
getPullToRefreshScrollDirection
的返回值决定了滑动的方向。返回
Orientation.HORIZONTAL
时为水平滑动;返回
Orientation.VERTICAL
时为竖直滑动。这里我们需要的是水平方向的滑动所以返回
Orientation.HORIZONTAL


@Override public Orientation getPullToRefreshScrollDirection() {
return Orientation.HORIZONTAL;
}


createRefreshableView

方法
createRefreshableView
的返回值是要添加刷新效果的控件,这里我们需要为横向滑动的 RecycleView 添加刷新效果所以就返回横向滑动的 RecycleView。

@Override protected RecyclerView createRefreshableView(Context context, AttributeSet attrs) {
RecyclerView recyclerView = new RecyclerView(context,attrs);
LinearLayoutManager mannagerTwo = new LinearLayoutManager(context);
mannagerTwo.setOrientation(LinearLayoutManager.HORIZONTAL);

recyclerView.setLayoutManager(mannagerTwo);

return recyclerView;
}


isReadyForPullStart

方法
isReadyForPullStart
返回
true
时表示可以开始刷新的效果了;返回
false
时表示还不满足可以触发刷新的效果。我们这里触发展示刷新效果的条件是 RecycleView 的第一个 item 的左边缘在屏幕左边缘的右侧。所以
isReadyForPullStart
的具体实现可以如下:

@Override protected boolean isReadyForPullStart() {
return isFirstItemVisible();
}


private boolean isFirstItemVisible() {
final RecyclerView.Adapter adapter = mRefreshableView.getAdapter();

if (null == adapter || adapter.getItemCount() ==0) {
if (DEBUG) {
Log.d(LOG_TAG, "isFirstItemVisible. Empty View.");
}
return true;
} else {

/**
* This check should really just be:
* mRefreshableView.getFirstVisiblePosition() == 0, but PtRListView
* internally use a HeaderView which messes the positions up. For
* now we'll just add one to account for it and rely on the inner
* condition which checks getTop().
*/
if (getFirstVisiblePosition() <= 1) {
final View firstVisibleChild = mRefreshableView.getChildAt(0);
if (firstVisibleChild != null) {
return firstVisibleChild.getLeft() >= mRefreshableView.getLeft();
}
}
}

return false;
}


isReadyForPullEnd

方法
isReadyForPullEnd
返回
true
时表示满足触发加载更多效果的条件,否则表示不满足。这里满足触发加载更多效果的条件是 RecycleView 最后一个 item 的右边缘在屏幕右边缘的左边。所以
isReadyForPullEnd
的实现如下:

@Override protected boolean isReadyForPullEnd() {
return isLastItemVisible();
}


private boolean isLastItemVisible() {
final RecyclerView.Adapter adapter = mRefreshableView.getAdapter();

if (null == adapter || adapter.getItemCount()==0) {
if (DEBUG) {
Log.d(LOG_TAG, "isLastItemVisible. Empty View.");
}
return true;
} else {
final int lastItemPosition = adapter.getItemCount() - 1;
final int lastVisiblePosition = getLastVisiblePosition();

if (DEBUG) {
Log.d(LOG_TAG, "isLastItemVisible. Last Item Position: "
+ lastItemPosition
+ " Last Visible Pos: "
+ lastVisiblePosition);
}

/**
* This check should really just be: lastVisiblePosition ==
* lastItemPosition, but PtRListView internally uses a FooterView
* which messes the positions up. For me we'll just subtract one to
* account for it and rely on the inner condition which checks
* getBottom().
*/
if (lastVisiblePosition >= lastItemPosition - 1) {
final int childIndex = lastVisiblePosition - getFirstVisiblePosition();
final View lastVisibleChild = mRefreshableView.getChildAt(childIndex);
if (lastVisibleChild != null) {
return lastVisibleChild.getRight() <= mRefreshableView.getRight();
}
}
}

return false;
}


完整代码

public class PullRefreshRecyclerView extends PullToRefreshBase<RecyclerView> {
public PullRefreshRecyclerView(Context context, Mode mode) {
super(context, mode);
}

public PullRefreshRecyclerView(Context context) {
super(context);
}

public PullRefreshRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
}

public PullRefreshRecyclerView(Context context, Mode mode, AnimationStyle animStyle) {
super(context, mode, animStyle);
}

@Override public Orientation getPullToRefreshScrollDirection() { return Orientation.HORIZONTAL; }

@Override protected RecyclerView createRefreshableView(Context context, AttributeSet attrs) {
RecyclerView recyclerView = new RecyclerView(context,attrs);
LinearLayoutManager mannagerTwo = new LinearLayoutManager(context);
mannagerTwo.setOrientation(LinearLayoutManager.HORIZONTAL);
//recyclerView.addItemDecoration(
// new DividerItemDecoration(this, DividerItemDecoration.HORIZONTAL_LIST));
recyclerView.setLayoutManager(mannagerTwo);

return recyclerView;
}

public void addItemDecoration(RecyclerView.ItemDecoration itemDecoration){
mRefreshableView.addItemDecoration(itemDecoration);
}

public void setAdapter(RecyclerView.Adapter adapter){
mRefreshableView.setAdapter(adapter);
}

@Override protected boolean isReadyForPullEnd() { return isLastItemVisible(); }

@Override protected boolean isReadyForPullStart() { return isFirstItemVisible(); }

private boolean isLastItemVisible() { final RecyclerView.Adapter adapter = mRefreshableView.getAdapter(); if (null == adapter || adapter.getItemCount()==0) { if (DEBUG) { Log.d(LOG_TAG, "isLastItemVisible. Empty View."); } return true; } else { final int lastItemPosition = adapter.getItemCount() - 1; final int lastVisiblePosition = getLastVisiblePosition(); if (DEBUG) { Log.d(LOG_TAG, "isLastItemVisible. Last Item Position: " + lastItemPosition + " Last Visible Pos: " + lastVisiblePosition); } /** * This check should really just be: lastVisiblePosition == * lastItemPosition, but PtRListView internally uses a FooterView * which messes the positions up. For me we'll just subtract one to * account for it and rely on the inner condition which checks * getBottom(). */ if (lastVisiblePosition >= lastItemPosition - 1) { final int childIndex = lastVisiblePosition - getFirstVisiblePosition(); final View lastVisibleChild = mRefreshableView.getChildAt(childIndex); if (lastVisibleChild != null) { return lastVisibleChild.getRight() <= mRefreshableView.getRight(); } } } return false; }

private int getFirstVisiblePosition(){
int position = 0;
RecyclerView.LayoutManager manager = mRefreshableView.getLayoutManager();
if (manager instanceof LinearLayoutManager){
LinearLayoutManager linearLayoutManager = (LinearLayoutManager) manager;
return linearLayoutManager.findFirstVisibleItemPosition();
}

return position;
}

private int getLastVisiblePosition(){
int position = 0;
RecyclerView.LayoutManager manager = mRefreshableView.getLayoutManager();
if (manager instanceof LinearLayoutManager){
LinearLayoutManager linearLayoutManager = (LinearLayoutManager) manager;
return linearLayoutManager.findLastVisibleItemPosition();
}
return position;
}

private boolean isFirstItemVisible() { final RecyclerView.Adapter adapter = mRefreshableView.getAdapter(); if (null == adapter || adapter.getItemCount() ==0) { if (DEBUG) { Log.d(LOG_TAG, "isFirstItemVisible. Empty View."); } return true; } else { /** * This check should really just be: * mRefreshableView.getFirstVisiblePosition() == 0, but PtRListView * internally use a HeaderView which messes the positions up. For * now we'll just add one to account for it and rely on the inner * condition which checks getTop(). */ if (getFirstVisiblePosition() <= 1) { final View firstVisibleChild = mRefreshableView.getChildAt(0); if (firstVisibleChild != null) { return firstVisibleChild.getLeft() >= mRefreshableView.getLeft(); } } } return false; }

}


结语

PullToReshHorizontalRecycleView 的用法和原有的 PullToReFresh 的控件是一样的,这里不再赘述。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐