RecyclerView实现下拉刷新和加载更多
2023-01-02 本文已影响0人
古早味蛋糕
一、介绍
RecyclerView的滑动事件,特别是下拉刷新和加载更多事件,现在几乎所有的APP显示数据列表时都会用到。今天在此记录一下自定义RecyclerView下拉刷新和加载更多的实现,主要是对滑动事件的监听和处理。
二、RecyclerView实现下拉刷新和加载更多
1、RecyclerView的滑动监听事件,监听上下滑动作
在RecyclerView的OnScrollListener滑动事件监听中有个好用的方法,就是onScrolled(RecyclerView recyclerView, int dx, int dy),其中根据dx的值的正负就可以判断是在左滑还是右滑,而根据dy的值就可以判断是在上滑还是下滑。
//上滑
if(dy>0){
//相应操作代码
}
//下滑
else if(dy<0){
//相应操作代码
}
2、判断是否滑到了列表的顶部或者列表底部
//是否滑到底部
if(!recyclerView.canScrollVertically(1)){
//相应处理操作
}
//是否滑到顶部
if(!recyclerView.canScrollVertically(-1)){
//相应处理操作
}
3、在RecyclerView实现自定义
知道了滑动事件的判断和处理,就可以很轻松得实现下拉刷新和加载更多了。
public class RefreshRecycleView extends RecyclerView implements RecyclerView.OnTouchListener {
private Boolean isLoadMore;//加载更多标志
private Boolean isLoadEnd;//加载到最后的标志
private Boolean isLoadStart;//顶部的标志
private Boolean isRefresh;//下拉刷新标志
private IOnScrollListener listener;//事件监听
private float mLastY;//监听移动的位置
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);
init();
}
/**
* 初始化
*/
public void init() {
isLoadEnd = false;
isLoadStart = true;
this.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
//SCROLL_STATE_DRAGGING 拖动时 和 SCROLL_STATE_IDLE 当屏幕停止滚动时
// SCROLL_STATE_SETTLING 要移动到最后位置时
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
loadData();
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
//上滑
if (dy > 0) {
//是否滑到底部
if (!recyclerView.canScrollVertically(1)) {
isLoadEnd = true;
} else {
isLoadEnd = false;
}
} else if (dy < 0) {
//是否滑到顶部
if (!recyclerView.canScrollVertically(-1)) {
isLoadStart = true;
} else {
isLoadStart = false;
}
}
}
});
this.setOnTouchListener(this);
}
/**
* 加载数据
*/
private void loadData() {
if (isLoadEnd) {
// 判断是否已加载所有数据
if (isLoadMore) {//未加载完所有数据,加载数据,并且还原isLoadEnd值为false,重新定位列表底部
if (getListener() != null) {
getListener().onLoadMore();
}
} else {//加载完了所有的数据
if (getListener() != null) {
getListener().onLoaded();
}
}
isLoadEnd = false;
} else if (isLoadStart) {
if (isRefresh) {
if (getListener() != null) {
getListener().onRefresh();
}
isLoadStart = false;
}
}
}
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (mLastY == -1) {
mLastY = motionEvent.getRawY();
}
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_MOVE:
final float deltaY = motionEvent.getRawY() - mLastY;
mLastY = motionEvent.getRawY();
//向上移动
if (deltaY < 0) {
//是否滑到底部
if (!this.canScrollVertically(1)) {
isLoadEnd = true;
} else {
isLoadEnd = false;
}
}
//向下移动
else if (deltaY > 0) {
//是否滑到顶部
if (!this.canScrollVertically(-1)) {
isLoadStart = true;
} else {
isLoadStart = false;
}
}
break;
case MotionEvent.ACTION_DOWN:
mLastY = motionEvent.getRawY();
break;
default://重置
mLastY = -1;
break;
}
return false;
}
//事件监听
public interface IOnScrollListener {
void onRefresh();
void onLoadMore();
void onLoaded();
}
public IOnScrollListener getListener() {
return listener;
}
//设置事件监听
public void setListener(IOnScrollListener listener) {
this.listener = listener;
}
public Boolean getLoadMore() {
return isLoadMore;
}
//设置是否支持加载更多
public void setLoadMoreEnable(Boolean loadMore) {
isLoadMore = loadMore;
}
public Boolean getRefresh() {
return isRefresh;
}
//设置是否支持下拉刷新
public void setRefreshEnable(Boolean refresh) {
isRefresh = refresh;
}
}
三、使用RefreshRecycleView实现刷新功能
1、定义布局
引用自定义的RefreshRecycleView就可以
activity_refresh.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".RefreshActivity">
<com.zyd.screenautosize.RefreshRecycleView
android:id="@+id/main_recycle_view_data"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
2、定义RecyclerView.Adapter
这里只是用系统自带的item布局
public class RefreshRecycleAdapter extends RecyclerView.Adapter<RefreshRecycleAdapter.ViewHolder> {
private List<String> list;
private Context context;
public RefreshRecycleAdapter(Context context, List<String> list) {
this.context = context;
this.list = list;
}
@Override
public RefreshRecycleAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_expandable_list_item_1, parent, false);
RefreshRecycleAdapter.ViewHolder viewHolder = new RefreshRecycleAdapter.ViewHolder(view);
return viewHolder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.text.setText(list.get(position));
holder.itemView.setTag(position);
}
@Override
public int getItemCount() {
return list.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
private TextView text;
public ViewHolder(View itemView) {
super(itemView);
text = itemView.findViewById(android.R.id.text1);
}
}
}
3、在Activity中初始化控件以及数据加载
public class RefreshActivity extends AppCompatActivity implements RefreshRecycleView.IOnScrollListener {
private RefreshRecycleView recycleView;//下拉刷新RecycleView
private List<String> list;//列表
private RefreshRecycleAdapter adapter;//Adapter
private AlertDialog.Builder builder;//提示框
private Dialog dialogProgress;
private static final int REFRESH_Load = 0;//下拉刷新
private static final int MORE_Load = 1;//加载更多
private Handler handler = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case REFRESH_Load:
recycleView.setLoadMoreEnable(true);
if (dialogProgress.isShowing()) {
dialogProgress.hide();
}
if (list != null) {
list.clear();
}
loadData();
adapter.notifyDataSetChanged();
break;
case MORE_Load:
recycleView.setLoadMoreEnable(false);
if (dialogProgress.isShowing()) {
dialogProgress.hide();
}
loadData();
adapter.notifyDataSetChanged();
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_refresh);
initView();
}
public void initView() {
builder = new AlertDialog.Builder(this);
setDialog(false);
list = new ArrayList<>();
loadData();
recycleView = findViewById(R.id.main_recycle_view_data);
final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(RefreshActivity.this);
recycleView.setLayoutManager(linearLayoutManager);
adapter = new RefreshRecycleAdapter(RefreshActivity.this, list);
recycleView.setAdapter(adapter);
recycleView.setListener(this);
recycleView.setRefreshEnable(true);
recycleView.setLoadMoreEnable(true);
}
/**
* 设置Dialog
* @param isShow
*/
private void setDialog(boolean isShow) {
builder.setView(R.layout.layout_progress);
dialogProgress = builder.create();
dialogProgress.setCanceledOnTouchOutside(false);
if (isShow) {
dialogProgress.show();
} else {
dialogProgress.dismiss();
}
}
/**
* 加载数据
*/
public void loadData() {
for (int i = 0; i < 10; i++) {
list.add("第" + i +"行");
}
}
@Override
public void onRefresh() {
if (!dialogProgress.isShowing()) {
dialogProgress.show();
}
new Thread() {
@Override
public void run() {
super.run();
try {
sleep(3000);
handler.sendEmptyMessage(REFRESH_Load);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
@Override
public void onLoadMore() {
if (!dialogProgress.isShowing()) {
dialogProgress.show();
}
new Thread() {
@Override
public void run() {
super.run();
try {
sleep(3000);
handler.sendEmptyMessage(MORE_Load);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
@Override
public void onLoaded() {
Toast.makeText(RefreshActivity.this, "Loaded all", Toast.LENGTH_SHORT).show();
}
}
4.效果图如下:
1.gif