一、介简
上一节写自定义RecyclerView实现了一个简单的下拉刷新与加载更多,这一节主要写外包RecyclerView方式实现的下拉刷新与加载更多,网上相关的内容有很多,不过内容太多不够简洁。所以想写一个以SwipeRefreshLayout外包SwipeRefreshLayout的实现简洁方式,不搞复杂化,主要以能快速看懂看会为主。
二、SwipeRefreshLayout
1、SwipeRefreshLayout是google官方推荐使用的下拉刷新的控件,如果用户想通过垂直滑动手势刷新视图的内容,就可以使用它。
具有使用简单,灵活等特点。不足的地方,不可以自定义刷新的头部和加载更多功能。
2、实例化此控件的Activity应添加一个 OnRefreshListener,以便在完成滑动刷新手势时收到通知。
SwipeRefreshLayout 会在每次手势再次完成时通知监听器,监听器负责确定何时实际启动其内容的刷新。如果监听器不需要有刷新动作,通过调用 setRefreshing(false) 来取消任何刷新的视觉指示。如果用户要禁用手势和进度动画,可以通过调用 setEnabled(false)实现。
3、SwipeRefreshLayout 经常与ListView RecyclerView CardView控件一起使用,用来刷新数据显示。
SwipeRefreshLayout 在xml文件中角色:它作为手势刷新视图的父布局控件,并且只支持一个直接子控件。
4、常用的API
方法 | 说明 |
---|---|
setRefreshing(boolean refreshing) | 设置刷新状态,true表示正在刷新,false表示取消刷新。 |
isRefreshing() | 判断当前的状态是否是正处于刷新状态。 |
setSize(int size) | 设置下拉刷新图标的大小, 只支持两种: DEFAULT 和 LARGE |
setColorSchemeResources(int…colorReslds) | 设置进度View的组合颜色,在手指上下滑时使用第一个颜色,在刷新中,会一个个颜色进行切换 |
setOnRefreshListener(SwipeRefreshLayout.OnRefreshListener listener) | 设置监听,需要重写onRefresh()方法,顶部下拉时会调用这个方法,在里面实现请求数据的逻辑,设置下拉进度条消失等等。 |
setProgressViewOffset(boolean scale, int start, int end) | 设置动画样式下拉的起始点和结束点,scale设置是否需要放大或者缩小动画, 第一个参数:默认为false,设置为true,下拉过程中刷新图标就会从小变大 第二个参数:起始位置,刷新图标距离顶部像素px 第三个参数:结束位置,刷新图标距离顶部像素px |
setProgressViewEndTarget(boolean scale, int end) | 设置动画样式下拉的结束点 scale设置是否需要放大或者缩小动画, 第二个参数:结束位置,刷新图标距离顶部像素px |
setSlingshotDistance(@Px int slingshotDistance) | 设置可以将刷新指示器拉出其静止位置的距离(以像素为单位) |
setEnabled(boolean enabled) | false:禁用手势下拉刷新动画 |
三、创建activity_swipe_recycler.xml与空类SwipeRecyclerActivity
1、在app的build.gradle配置文件里导入
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
2、activity_swipe_recycler.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/purple_500"
app:popupTheme="@style/ToolbarPopupTheme"
app:theme="@style/ThemeOverlay.AppCompat.Dark"
app:titleTextColor="@android:color/white" />
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</LinearLayout>
布局主要一个SwipeRefreshLayout外包一个RecyclerView
四、创建Adapter与Adapter布局
1、adapter_load_more.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="60dp">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
card_view:cardCornerRadius="8dp">
<TextView
android:id="@+id/tv_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="1"
android:textColor="#D4237A"
android:textSize="25sp" />
</androidx.cardview.widget.CardView>
</RelativeLayout>
2、创建 LoadMoreAdapter
public class LoadMoreAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<String> dataList;
// 普通布局
private final int TYPE_ITEM = 1;
// 脚布局
private final int TYPE_FOOTER = 2;
// 当前加载状态,默认为加载完成
private int loadState = 2;
// 正在加载
public final int LOADING = 1;
// 加载完成
public final int LOADING_COMPLETE = 2;
// 加载到底
public final int LOADING_END = 3;
public LoadMoreAdapter(List<String> dataList) {
this.dataList = dataList;
}
@Override
public int getItemViewType(int position) {
// 最后一个item设置为FooterView
if (position + 1 == getItemCount()) {
return TYPE_FOOTER;
} else {
return TYPE_ITEM;
}
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == TYPE_ITEM) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_load_more, parent, false);
return new RecyclerViewHolder(view);
} else if (viewType == TYPE_FOOTER) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_refresh_footer, parent, false);
return new FootViewHolder(view);
}
return null;
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if (holder instanceof RecyclerViewHolder){
RecyclerViewHolder recyclerViewHolder = (RecyclerViewHolder) holder;
recyclerViewHolder.tvItem.setText(dataList.get(position));
}else if (holder instanceof FootViewHolder){
FootViewHolder footViewHolder = (FootViewHolder) holder;
switch (loadState){
case LOADING:// 正在加载
footViewHolder.pbLoading.setVisibility(View.VISIBLE);
footViewHolder.tvLoading.setVisibility(View.VISIBLE);
footViewHolder.llEnd.setVisibility(View.GONE);
break;
case LOADING_COMPLETE: // 加载完成
footViewHolder.pbLoading.setVisibility(View.INVISIBLE);
footViewHolder.tvLoading.setVisibility(View.INVISIBLE);
footViewHolder.llEnd.setVisibility(View.GONE);
break;
case LOADING_END:// 加载到底
footViewHolder.pbLoading.setVisibility(View.GONE);
footViewHolder.tvLoading.setVisibility(View.GONE);
footViewHolder.llEnd.setVisibility(View.VISIBLE);
break;
}
}
}
@Override
public int getItemCount() {
return dataList.size()+1;
}
private class RecyclerViewHolder extends RecyclerView.ViewHolder {
TextView tvItem;
RecyclerViewHolder(View itemView) {
super(itemView);
tvItem = itemView.findViewById(R.id.tv_item);
}
}
@Override
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
super.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) {
// 如果当前是footer的位置,那么该item占据2个单元格,正常情况下占据1个单元格
return getItemViewType(position) == TYPE_FOOTER ? gridLayoutManager.getSpanCount():1;
}
});
}
}
private class FootViewHolder extends RecyclerView.ViewHolder {
ProgressBar pbLoading;
TextView tvLoading;
LinearLayout llEnd;
public FootViewHolder(@NonNull View itemView) {
super(itemView);
pbLoading = itemView.findViewById(R.id.pb_loading);
tvLoading = itemView.findViewById(R.id.tv_loading);
llEnd = itemView.findViewById(R.id.ll_end);
}
}
/**
* 设置上拉加载状态
*
* @param loadState 0.正在加载 1.加载完成 2.加载到底
*/
public void setLoadState(int loadState){
this.loadState = loadState;
notifyDataSetChanged();
}
}
五、在SwipeRecyclerActivity里进行初始化与加载数据
1、SwipeRecyclerActivity的具体实现
public class SwipeRecyclerActivity extends AppCompatActivity {
private Toolbar toolbar;
private SwipeRefreshLayout swipeRefreshLayout;
private RecyclerView recyclerView;
private LoadMoreAdapter loadMoreAdapter;
private List<String> dataList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_swipe_recycler);
init();
}
private void init() {
toolbar = findViewById(R.id.toolbar);
swipeRefreshLayout = findViewById(R.id.swipe_refresh_layout);
recyclerView = findViewById(R.id.recycler_view);
// 使用Toolbar替换ActionBar
setSupportActionBar(toolbar);
// 设置刷新控件颜色
swipeRefreshLayout.setColorSchemeColors(Color.parseColor("#4DB6AC"));
// 模拟获取数据
getData();
loadMoreAdapter = new LoadMoreAdapter(dataList);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(loadMoreAdapter);
// 设置下拉刷新
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
// 刷新数据
if (dataList.size()>0){
dataList.clear();
}
getData();
loadMoreAdapter.notifyDataSetChanged();
// 延时1s关闭下拉刷新
swipeRefreshLayout.postDelayed(new Runnable() {
@Override
public void run() {
if (swipeRefreshLayout != null && swipeRefreshLayout.isRefreshing()) {
swipeRefreshLayout.setRefreshing(false);
}
}
}, 2000);
}
});
// 设置加载更多监听
recyclerView.addOnScrollListener(new EndlessRecyclerOnScrollListener() {
@Override
public void onLoadMore() {
loadMoreAdapter.setLoadState(loadMoreAdapter.LOADING);
if (dataList.size() < 52) {
// 模拟获取网络数据,延时1s
new Timer().schedule(new TimerTask() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
getData();
loadMoreAdapter.setLoadState(loadMoreAdapter.LOADING_COMPLETE);
}
});
}
}, 2000);
} else {
// 显示加载到底的提示
loadMoreAdapter.setLoadState(loadMoreAdapter.LOADING_END);
}
}
});
}
private void getData() {
String letter ="Item";
for (int i = 0; i < 30; i++) {
dataList.add(letter+i);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.layout_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.liner:
recyclerView.setLayoutManager(new LinearLayoutManager(this));
break;
case R.id.grid:
recyclerView.setLayoutManager(new GridLayoutManager(this, 2));
break;
}
dataList.clear();
getData();
recyclerView.setAdapter(loadMoreAdapter);
return super.onOptionsItemSelected(item);
}
}
2、EndlessRecyclerOnScrollListener的抽象类实现
public abstract class EndlessRecyclerOnScrollListener extends RecyclerView.OnScrollListener {
// 用来标记是否正在向上滑动
private boolean isSlidingUpward = false;
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
//当recyclerview 不滑动时
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
// 获取最后一个完全显示的itemPosition
int lastItemPosition = layoutManager.findLastCompletelyVisibleItemPosition();
int itemCount = layoutManager.getItemCount();
// 判断是否滑动到了最后一个item,并且是向上滑动
if (lastItemPosition == (itemCount - 1) && isSlidingUpward) {
// 加载更多
onLoadMore();
}
}
}
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
// 大于0表示正在向上滑动,小于等于0表示停止或向下滑动
isSlidingUpward = dy > 0;
}
//加载更多回调
public abstract void onLoadMore();
}
完整代码:https://gitee.com/zyd_gitee/recycler-view-refresh-demo.git
![](https://img.haomeiwen.com/i2639112/eacd15b1295b8d68.gif)
网友评论