效果图:
此篇博客是在上一篇: Recylerview上拉加载与下拉刷新(一)的升级版,如果有不清楚先看 Recylerview上拉加载与下拉刷新(一)
(p.s. 这是我正在写的一个毕业设计,前端App使用Rxjava + Retrofit + EventBus; Java后台是 SSM
github地址:https://github.com/uweii/SHShop 每天都会更新代码)
1)上拉加载:
定义一个footview.xml:
adapter:
package com.up.uwei.shshop.adapter;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.LinearInterpolator;
import android.widget.ImageView;
import android.widget.TextView;
import com.squareup.picasso.Callback;
import com.squareup.picasso.Picasso;
import com.up.uwei.shshop.Configs;
import com.up.uwei.shshop.R;
import com.up.uwei.shshop.activity.GoodsDetailActivity;
import com.up.uwei.shshop.activity.RegActivity;
import com.up.uwei.shshop.fragment.ShopFragment;
import com.up.uwei.shshop.pojo.Goods;
import java.util.ArrayList;
public class ShopRecylerViewAdapter extends RecyclerView.Adapter {
private int FOOTVIEW = 1;
private int NORMALVIEW = 2;
private ArrayList mGoods = new ArrayList<>();
private Context mContext;
private Animation mAnimation ;
public ShopRecylerViewAdapter(Context context){
this.mContext = context;
mAnimation = AnimationUtils.loadAnimation(context, R.anim.loading_anim);
DecelerateInterpolator di = new DecelerateInterpolator();
mAnimation.setInterpolator(di);
}
public ArrayList getGoods() {
return mGoods;
}
public void setGoods(ArrayList goods) {
mGoods = goods;
}
public void cleanGoods() {
mGoods.clear();
}
public void addGoods(ArrayList goods){
mGoods.addAll(goods);
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
if(viewType == NORMALVIEW){
View v = inflater.inflate(R.layout.item_shop,parent,false);
return new ShopHolder(v);
}else {
View v = inflater.inflate(R.layout.foot_view, parent, false);
return new FootHolder(v);
}
}
@Override
public int getItemViewType(int position) {
if (position +1 == getItemCount()){ //如果position到了最后一个显示 footview
return FOOTVIEW;
}else {
return NORMALVIEW;
}
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if(holder instanceof ShopHolder){
ShopHolder hold = (ShopHolder) holder;
Goods goods = mGoods.get(position);
String[] imgs = Configs.getImgs(goods.getImgs());
String tag = Configs.getTag(goods.getTag());
Picasso.with(holder.itemView.getContext()).load(Configs.BASE_URL + "/images/" + (imgs == null? "":imgs[0])).placeholder(R.drawable.placeholder).error(R.drawable.load_error).fit().into(((ShopHolder) holder).iv_photo);
hold.tv_name.setText(goods.getName());
hold.tv_tag.setText(tag);
hold.tv_place.setText(goods.getPlace());
hold.tv_price.setText("¥"+goods.getPrice());
hold.tv_saleCount.setText(goods.getSalecount() + "人付款");
hold.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(mContext, GoodsDetailActivity.class);
mContext.startActivity(intent);
}
});
}else {
//为Recylerview所在的fragment.java设置回调方法,用来控制footview的显示隐藏
FootHolder h = (FootHolder) holder;
ShopFragment.CallBack callBack = new ShopFragment.CallBack() {
@Override
public void onDismiss() {
holder.itemView.setVisibility(View.INVISIBLE);
h.mLoading.clearAnimation();
}
@Override
public void onShow() {
holder.itemView.setVisibility(View.VISIBLE);
h.mLoading.startAnimation(mAnimation);
}
};
ShopFragment.setMyCallBack(callBack);
}
}
@Override
public int getItemCount() { //因为多了一个footview,所以在原来基础上加一
return mGoods.size() + 1;
}
//正常商品holder
class ShopHolder extends RecyclerView.ViewHolder{
TextView tv_name, tv_price, tv_place, tv_tag, tv_saleCount;
ImageView iv_photo;
public ShopHolder(View itemView) {
super(itemView);
iv_photo = itemView.findViewById(R.id.iv_photo);
tv_name = itemView.findViewById(R.id.tv_name);
tv_tag = itemView.findViewById(R.id.tv_tag);
tv_place = itemView.findViewById(R.id.tv_college);
tv_price = itemView.findViewById(R.id.tv_price);
tv_saleCount = itemView.findViewById(R.id.tv_saleCount);
// tv_name = itemView.findViewByI
}
}
//底部加载holder
class FootHolder extends RecyclerView.ViewHolder{
public TextView mTextView;
public ImageView mLoading;
public FootHolder(View itemView) {
super(itemView);
mLoading = itemView.findViewById(R.id.iv_loading);
}
}
}
fragment.java
package com.up.uwei.shshop.fragment;
import android.content.Intent;
import android.graphics.LinearGradient;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.Fragment;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.up.uwei.shshop.BaseFragment;
import com.up.uwei.shshop.Configs;
import com.up.uwei.shshop.R;
import com.up.uwei.shshop.activity.SearchActivity;
import com.up.uwei.shshop.adapter.ShopRecylerViewAdapter;
import com.up.uwei.shshop.event.Event;
import com.up.uwei.shshop.pojo.Goods;
import com.up.uwei.shshop.pojo.SearchBean;
import com.up.uwei.shshop.service.RetrofitService;
import com.up.uwei.shshop.utils.LogUtil;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.w3c.dom.Text;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Timer;
import java.util.TimerTask;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.Unbinder;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import okhttp3.ResponseBody;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import static android.view.View.VISIBLE;
public class ShopFragment extends BaseFragment implements SwipeRefreshLayout.OnRefreshListener {
@BindView(R.id.tv_search_hint)
TextView mSearHint;
@BindView(R.id.recylerView)
RecyclerView mRecyclerView;
@BindView(R.id.fab)
FloatingActionButton mFab;
@BindView(R.id.swipefresh)
SwipeRefreshLayout mRefreshLayout;
private boolean mRefresh = false;
private GridLayoutManager manager;
private int mLastPosition = 0; //滑到这里开始加载
// private int mCurrentOffset = 0; //从后台查询数据库下标
// private int mLength = 20; //每次查询20条
private Timer mTimer = null;
private Unbinder mUnbinder; //ButterKnife解绑
private ArrayList mGoods;
private ShopRecylerViewAdapter mAdapter;
private boolean isGettingNow = false; //标志现在是否在请求数据
public static ShopFragment newInstance(){
ShopFragment fragment = new ShopFragment();
Bundle bundle = new Bundle();
fragment.setArguments(bundle);
return fragment;
}
/*
* 定义footview回调接口
* 控制footview的显示和隐藏
* */
public interface CallBack{
void onDismiss();
void onShow();
}
private static CallBack myCallBack;
public static void setMyCallBack(CallBack callBack){
myCallBack = callBack;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EventBus.getDefault().register(this);
SearchBean searchBean = new SearchBean(0,20,2,null,null);
getGoods(searchBean);
}
private void getGoods(SearchBean searchBean){
if(isGettingNow){
return;
}
isGettingNow = true;
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Configs.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
RetrofitService service = retrofit.create(RetrofitService.class);
service.getGoods(searchBean.getOffset(), searchBean.getLength(),searchBean.getKey(),
searchBean.getPlace(),searchBean.getSecondhand())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(ArrayList goods) {
if (mRefresh){
mAdapter.cleanGoods();
mAdapter.notifyDataSetChanged();
}
LogUtil.d("getGoods============");
if(goods.size() > 0){
mTimer.schedule(new TimerTask() {
@Override
public void run() {
Event event = new Event("add",2);
event.setGoods(goods);
EventBus.getDefault().post(event);
isGettingNow = false;
if (mRefreshLayout.isRefreshing()){
mRefreshLayout.setRefreshing(false);
mRefresh = false;
}
}
},1000);
}
isGettingNow = false;
}
@Override
public void onError(Throwable e) {
Event event = new Event("dismiss", 3);
mTimer.schedule(new TimerTask() {
@Override
public void run() {
EventBus.getDefault().post(event); //没有获取到数据,隐藏footview
isGettingNow = false;
}
},1000);
}
@Override
public void onComplete() {
}
});
}
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void setTimer(Event event){
if (event.getMessage().equals("timer") && event.getTime() == 1){
SearchBean searchBean = new SearchBean(manager.getItemCount(), 20, 2,null,null);
getGoods(searchBean);
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void addGoods(Event event){
if (event.getMessage().equals("add") && event.getTime() == 2){
mAdapter.addGoods(event.getGoods());
mAdapter.notifyDataSetChanged();
}else if(event.getMessage().equals("dismiss") && event.getTime() == 3){
myCallBack.onDismiss();
}
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.shop_fragment, container,false);
mUnbinder = ButterKnife.bind(this, v);
mRecyclerView = v.findViewById(R.id.recylerView);
init();
manager = new GridLayoutManager(getActivity(), 2);
manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
boolean isFooter = position == mAdapter.getItemCount() - 1;
return isFooter ? 2:1;
}
});
mRecyclerView.setLayoutManager(manager);
mRecyclerView.setAdapter(mAdapter);
return v;
}
private void init(){
mTimer = new Timer();
mAdapter = new ShopRecylerViewAdapter(getActivity());
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if(newState == RecyclerView.SCROLL_STATE_IDLE){
if(mLastPosition + 1 == manager.getItemCount()){
//加载更多
myCallBack.onShow(); //在最后一个item处上拉时,显示footview
SearchBean searchBean = new SearchBean(manager.getItemCount(), 20, 2, null, null);
getGoods(searchBean);
}
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
mLastPosition = manager.findLastVisibleItemPosition();
if (dy > 0 && mFab.getVisibility() == VISIBLE) {
mFab.hide();
} else if (dy < 0 && mFab.getVisibility() != VISIBLE) {
mFab.show();
}
}
});
//设置显示刷新时的颜色
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()方法
}
@OnClick({R.id.tv_search_hint, R.id.fab})
public void click(View v){
switch (v.getId()){
case R.id.tv_search_hint:
Intent intent = new Intent(getActivity(), SearchActivity.class);
startActivity(intent);
break;
case R.id.fab:
mRecyclerView.smoothScrollToPosition(0); //滑动到第一项
break;
}
}
@Override
public void onDestroy() {
super.onDestroy();
mUnbinder.unbind();
EventBus.getDefault().unregister(this);
if (mTimer != null){
mTimer.cancel();
mTimer = null;
}
}
@Override
public void onRefresh() {
mRefresh = true;
mRefreshLayout.setRefreshing(true);
SearchBean searchBean = new SearchBean(0,20,2,null,null);
getGoods(searchBean);
}
}
另外加载时使用了动画的
记得,在隐藏footview时,先清除动画。
主要就是,在fragment的代码里定义回调接口,然后在adapter里显示item时来绑定接口,
之后便可以在fragment里控制,footview的显示和隐藏了。
判断上拉,
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if(newState == RecyclerView.SCROLL_STATE_IDLE){
if(mLastPosition + 1 == manager.getItemCount()){ //当前显示最后一个item
//加载更多
myCallBack.onShow();
SearchBean searchBean = new SearchBean(manager.getItemCount(), 20, 2, null, null);
getGoods(searchBean);
}
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
mLastPosition = manager.findLastVisibleItemPosition(); //记录最后一个item位置
if (dy > 0 && mFab.getVisibility() == VISIBLE) {
mFab.hide();
} else if (dy < 0 && mFab.getVisibility() != VISIBLE) {
mFab.show();
}
}
});
因为,代码里的注释很清楚了,就不多写了。