这篇博客记载了,recylerview上拉加载,下拉刷新,当recylerview是GridLayout时设置显示footView[提示正在加载中的布局]占满一行,和监听recylerview滑到最后一项就加载数据。
在用Recylerview展示数据时,不可能一次性获取全部数据,而是用户需要多少就从网络获取多少,因此在RecylerView里经常时滑到最后一条数据时就去加载更多的数据。
如下图:
首先讲 下拉刷新:
在RecylerView外层套个SwipeRefreshLayout就行,然后给SwipeRefreshLayout加上侦听:
代码加上侦听控制刷新时的显示:
mRefreshLayout = view.findViewById(R.id.swipeRefresh);
//设置显示刷新时的颜色 mRefreshLayout.setColorSchemeResources(android.R.color.holo_blue_light, android.R.color.holo_red_light,
android.R.color.holo_orange_light, android.R.color.holo_green_light);
mRefreshLayout.setOnRefreshListener(this); //添加监听,重写onFresh()方法
//设置显示刷新时的颜色 mRefreshLayout.setColorSchemeResources(android.R.color.holo_blue_light, android.R.color.holo_red_light,
android.R.color.holo_orange_light, android.R.color.holo_green_light);
mRefreshLayout.setOnRefreshListener(this); //添加监听,重写onFresh()方法
可以看到,当下拉时,onRefresh会触发,然后我通过mRefreahLayout.setRefreshing(true)控制使它显示刷新
之后在onPostExecute里面,即网络请求数据完成后,通过setRefreshing(false)来停止刷新,并notifyDataChanged().
上拉加载
首先我们定义两个布局,一个是正常的盛装item布局,一个是提示在加载的布局:
正常item布局:
提示在加载的布局文件:
然后创建两个ViewHolder:
重写getItemViewType,
如果滑到最后一项,就返回 FootView(定义的一个int变量,值为 1),否则返回正常的NormalView(值为 0)。
在onCreateViewHolder里面根据viewType来判断到底加载哪个layout:
然后在onBindViewHolder里面根据holder的类型,来显示不同的内容【显示正常item内容或是 加载提示内容】
因为你最后显示到最后一条多显示的一个footView,所以在getItemCount里面要多+1;
.
这样就能够实现,当显示item时,根据itemType返回的type的不同,进而返回的ViewHolder不同,然后在onBindViewHolder里面根据不同的holder显示不同的内容,因此在最后一项,会显示加载的布局,否则显示正常的item布局啦.
然后因为我是GridLayoutManager,所以在显示加载中的布局时要设置它占3列,其余的就让它占一列就好:
根据position是否是最后一个来决定占的列数。
在recylerview添加滑动侦听,如果当前是最后一项就加载更多数据:
完整代码:
public class Fragment_Movie_Types extends Fragment implements SwipeRefreshLayout.OnRefreshListener {
private static String TAG = "Fragment_Movie_Types";
private RecyclerView mRecyclerView;
private SwipeRefreshLayout mRefreshLayout;
private String tag;
private int lastItemPosition; //最后一个item的位置
private int mCurrentStart = 0; //请求电影的起始位置
private int NormalView = 0; //正常item
private int FootView = 1; //加载view
private List<MovieInfo> mMovieInfos = new ArrayList<>();
private TypeAdapter adapter;
public int mMovieType; //电影种类
/*1. 爱情篇
*2. 喜剧
*3. 动画
*4. 科幻
*5. 动作
*6. 经典
* */
public Fragment newInstance(int movieType) {
Fragment_Movie_Types fragment = new Fragment_Movie_Types();
fragment.mMovieType = movieType;
return fragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
adapter = new TypeAdapter();
Log.i(TAG, "mMovieType====>" + mMovieType + "onCreate");
Log.i(TAG, "mMovieType===> " + this.mMovieType);
switch (this.mMovieType) {
case 1:
tag = "爱情";
break;
case 2:
tag = "喜剧";
break;
case 3:
tag = "动画";
break;
case 4:
tag = "科幻";
break;
case 5:
tag = "动作";
break;
case 6:
tag = "经典";
break;
}
Log.i(TAG, "tag==> " + tag);
AsyncTask<String, Integer, List<MovieInfo>> task = new AsyncTask<String, Integer, List<MovieInfo>>() {
@Override
protected List<MovieInfo> doInBackground(String... strings) {
return new FetchMovies().getMoviesByTag(tag, mCurrentStart);
}
@Override
protected void onPostExecute(List<MovieInfo> movieInfos) {
super.onPostExecute(movieInfos);
mMovieInfos = movieInfos;
adapter.notifyDataSetChanged();
Log.i(TAG, "网络请求结束");
}
};
task.execute();
setRetainInstance(true);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_movie_types, container, false);
mRecyclerView = view.findViewById(R.id.recyler_view);
mRefreshLayout = view.findViewById(R.id.swipeRefresh);
mRefreshLayout.setColorSchemeResources(android.R.color.holo_blue_light, android.R.color.holo_red_light,
android.R.color.holo_orange_light, android.R.color.holo_green_light);
mRefreshLayout.setOnRefreshListener(this);
final GridLayoutManager lm = new GridLayoutManager(getActivity(), 3);
lm.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
//如果是最后一个item,则设置占据3列,否则占据1列
@Override
public int getSpanSize(int position) {
boolean isFooter = position == adapter.getItemCount() - 1;
return isFooter ? 3 : 1;
}
});
mRecyclerView.setLayoutManager(lm);
mRecyclerView.setAdapter(adapter);
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
// Log.d(TAG, "current state==> " + newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
Log.d(TAG, "SCROLL_STATE_IDEL");
if (lastItemPosition + 1 == lm.getItemCount()) {
//Log.d(TAG, "我在加载更多");
mCurrentStart++;
loadMore();
}
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
//Log.d(TAG, "onScrolled");
lastItemPosition = lm.findLastVisibleItemPosition();
}
});
return view;
}
@Override
public void onRefresh() {
mRefreshLayout.setRefreshing(true);
AsyncTask<String, Integer, List<MovieInfo>> task = new AsyncTask<String, Integer, List<MovieInfo>>() {
@Override
protected List<MovieInfo> doInBackground(String... strings) {
return new FetchMovies().getMoviesByTag(tag, 0);
}
@Override
protected void onPostExecute(List<MovieInfo> movieInfos) {
super.onPostExecute(movieInfos);
mMovieInfos.clear();
mMovieInfos = movieInfos;
adapter.notifyDataSetChanged();
mRefreshLayout.setRefreshing(false);
Log.i(TAG, "网络请求结束");
}
};
task.execute();
}
public class TypeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(getActivity());
if (viewType == NormalView) {
View v = inflater.inflate(R.layout.movie_item, parent, false);
return new TypeHolder(v);
} else {
View v = inflater.inflate(R.layout.footview, parent, false);
return new FootHolder(v);
}
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
if (holder instanceof TypeHolder) {
((TypeHolder) holder).movieName.setText(mMovieInfos.get(position).getName());
Picasso.with(getActivity()).load(mMovieInfos.get(position).getImgUrl()).into(((TypeHolder) holder).movieImg);
} else {
((FootHolder)holder).mTip.setText("正在努力加载中...");
}
}
@Override
public int getItemCount() {
if (mMovieInfos != null) {
return mMovieInfos.size() + 1;
} else {
return 0;
}
}
@Override
public int getItemViewType(int position) {
if (position + 1 == getItemCount()) {
return FootView;
} else {
return NormalView;
}
}
class TypeHolder extends ViewHolder { //普通电影的holder
public ImageView movieImg;
public LinearLayout starContainer;
public TextView movieName;
public TypeHolder(View itemView) {
super(itemView);
movieImg = itemView.findViewById(R.id.movie_img);
movieName = itemView.findViewById(R.id.movie_name);
starContainer = itemView.findViewById(R.id.star_container);
}
}
class FootHolder extends ViewHolder { //提示加载的holder
public TextView mTip;
public FootHolder(View itemView) {
super(itemView);
mTip = itemView.findViewById(R.id.tv_tip);
}
}
}
private void loadMore() {
final AsyncTask<String, Integer, List<MovieInfo>> task = new AsyncTask<String, Integer, List<MovieInfo>>() {
@Override
protected List<MovieInfo> doInBackground(String[] objects) {
return new FetchMovies().getMoviesByTag(tag, mCurrentStart*20);
}
@Override
protected void onPostExecute(List<MovieInfo> o) {
super.onPostExecute(o);
mMovieInfos.addAll(o);
adapter.notifyDataSetChanged();
}
};
task.execute();
}
}