最近在做一个新的app,有一个分页加载的功能需要用到上拉加载。自己搜了很多关于RecycleView上拉加载的资料,代码都写了很多,引用这些第三方,徒增apk的体积。所以情急之下,自己写了一个上拉加载(该方案也实现了下拉刷新)。废话不多说,先看效果图:
是不是有点上拉加载的意思?
思路:其实很简单,我在当前的Fragment里做了2个标签,一个是isShowBottom用来判断是否显示“已下拉到底部”,一个是isLoadBottom用来判断是否进行上拉加载。然后在适配器里做了个布局的判断加载,来控制进度条和文本的显隐,就是如果有数据需要上拉加载就显示进度条,否则显示文本“已下拉到底部”。代码如下:
1. Fragment相关代码:
public class VisitFragment extends BaseFragment {
private Gson gson;
private VisitAdapter visitAdapter;
private List<jsonVisit> lists = new ArrayList<jsonVisit>();
private List<jsonVisit> list = new ArrayList<jsonVisit>();
private int maxCount = Constants.MAX_COUNT;
private int offset = Constants.OFFSET;
private int currentIndex = 0;
private boolean isFirst = true;
public static boolean isLoadBottom = false;
public static boolean isShowBottom = false;
@ViewInject(R.id.rv_layout_recyclerView_srl)
private RecyclerView recyclerView;
@ViewInject(R.id.srl_layout_recyclerView)
private SwipeRefreshLayout srl;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
gson = gson == null ? new Gson() : gson;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View visitFragment = inflater.inflate(R.layout.fragment_visit, container, false);
return visitFragment;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
x.view().inject(this, view);
setViews();
setListeners();
}
private void setViews() {
srl.setColorSchemeColors(x.app().getResources().getColor(R.color.color_jcdecaux));
srl.setRefreshing(true);
LinearLayoutManager manager = new LinearLayoutManager(getActivity());
// recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL));
recyclerView.setLayoutManager(manager);
setServerData();
}
private void setServerData() {
if (OtherAction.hasNet()) {
setData();
} else {
llRefresh.setVisibility(View.VISIBLE);
}
}
private void setData() {
String url = ServerConfig.getFullURL(x.app().getString(R.string.url_visit));
RequestParams params = OtherAction.createParams(url);
params.addQueryStringParameter("offset", String.valueOf(offset));
params.addQueryStringParameter("maxCount", String.valueOf(maxCount));
if (getArguments() == null) return;
try {
x.http().get(params, new Callback.CommonCallback<String>() {
@Override
public void onSuccess(String result) {
jsonBase jsonBase = gson.fromJson(result, jsonBase.class);
srl.setRefreshing(false);
list = gson.fromJson(gson.toJson(jsonBase.getList()), new TypeToken<List<jsonVisit>>() {
}.getType());
if (list.size() != 0) {
isShowBottom = true;
lists.addAll(list);
if (lists.size() <= 5) {//页面少于5条数据显示 加载到底部
isLoadBottom = true;
} else {
isLoadBottom = false;
}
if (list.size() < maxCount) {
currentIndex = list.size();
} else {
currentIndex = maxCount;
}
offset += currentIndex;
} else {
if (lists.size() == 0) {
isShowBottom = false;
} else {
isShowBottom = true;
isLoadBottom = true;
}
}
if (isFirst) {// 首次加载初始化适配器,否则刷新数据
visitAdapter = new VisitAdapter(list);
recyclerView.setAdapter(visitAdapter);
isFirst = false;
} else {
visitAdapter.notifyDataSetChanged();
}
setRvListener();
}
@Override
public void onError(Throwable ex, boolean isOnCallback) {
}
@Override
public void onCancelled(CancelledException cex) {
}
@Override
public void onFinished() {
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
private void setRvListener() {
if (visitAdapter != null) {
visitAdapter.setOnItemClickListener(new VisitAdapter.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
}
});
}
}
private void setListeners() {
srl.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
if (OtherAction.hasNet()) {
refreshData();
} else {
srl.setRefreshing(false);
}
}
});
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
LinearLayoutManager manager = (LinearLayoutManager) recyclerView.getLayoutManager();
int lastPos = manager.findLastVisibleItemPosition();
if (lastPos == manager.getItemCount() - 1) {
if (list.size() != 0) {
offset += currentIndex;
setData();
}
}
}
}
});
}
/**
* 下拉更新数据
*/
private void refreshData() {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(Constants.SLEEPTIME_REFRESH);
} catch (InterruptedException e) {
e.printStackTrace();
}
setData();
}
}).start();
}
}
2. 适配器相关代码:
/**
* Create by ah , date on 2019/8/2
* 待拜访
*/
public class VisitAdapter extends RecyclerView.Adapter<VisitAdapter.ViewHolder> implements View.OnClickListener {
private OnItemClickListener itemClick = null;
private List<jsonVisit> list = new ArrayList<jsonVisit>();
private static final int NORMAL_VIEW = 1;
private static final int FOOT_VIEW = 2;
public VisitAdapter(List<jsonVisit> list) {
this.list = list;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
@ViewInject(R.id.tv_item_visit_title)
private TextView tvTitle;
@ViewInject(R.id.tv_item_visit_brand)
private TextView tvBrand;
@ViewInject(R.id.tv_item_visit_address)
private TextView tvAddress;
@ViewInject(R.id.tv_item_visit_title1)
private TextView tvTitle1;
@ViewInject(R.id.tv_item_visit_date1)
private TextView tvDate1;
@ViewInject(R.id.tv_item_visit_content1)
private TextView tvContent1;
@ViewInject(R.id.tv_item_visit_detail1)
private TextView tvDetail1;
@ViewInject(R.id.tv_item_visit_title2)
private TextView tvTitle2;
@ViewInject(R.id.tv_item_visit_date2)
private TextView tvDate2;
@ViewInject(R.id.tv_item_visit_content2)
private TextView tvContent2;
@ViewInject(R.id.tv_item_visit_detail2)
private TextView tvDetail2;
@ViewInject(R.id.ll_item_visit_content2)
private LinearLayout llContent2;
private PercentFrameLayout view;
private LinearLayout footView;
private TextView tvBottom;
private ProgressBar pb;
public ViewHolder(View itemView, int viewType) {
super(itemView);
if (viewType == NORMAL_VIEW) {
x.view().inject(this, itemView);
} else if (viewType == FOOT_VIEW) {
footView = (LinearLayout) itemView;
tvBottom = footView.findViewById(R.id.tv_layout_recyclerview_bottom);
pb = footView.findViewById(R.id.pb_layout_recyclerview_bottom);
}
}
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View visitView;
visitView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_visit, parent, false);
if (viewType == FOOT_VIEW)
visitView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.layout_recyclerview_bottom, parent, false);
ViewHolder holder = new ViewHolder(visitView, viewType);
visitView.setOnClickListener(this);
return holder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
if (getItemViewType(position) == NORMAL_VIEW) {
jsonVisit jsonVisit = list.get(position);
holder.tvTitle.setText(jsonVisit.getUserName());
holder.tvBrand.setText(jsonVisit.getCompanyName());
holder.tvAddress.setText(jsonVisit.getAddress());
holder.tvTitle1.setText(jsonVisit.getVisitPlanTitle());
holder.tvDate1.setText(jsonVisit.getVisitPlanDate());
holder.tvContent1.setText(jsonVisit.getVisitPlanPurpose() + Constants.LINE + jsonVisit.getVisitPlanMethod());
holder.tvDetail1.setText(jsonVisit.getVisitPlanSummary());
if (jsonVisit.getVisitPurpose() != null) {
holder.llContent2.setVisibility(View.VISIBLE);
holder.tvTitle2.setText(jsonVisit.getVisitTitle());
holder.tvDate2.setText(jsonVisit.getVisitDate());
holder.tvContent2.setText(jsonVisit.getVisitPurpose() + Constants.LINE + jsonVisit.getVisitMethod());
holder.tvDetail2.setText(jsonVisit.getVisitSummary());
} else {
holder.llContent2.setVisibility(View.GONE);
}
holder.itemView.setTag(position);
} else {
if (VisitFragment.isShowBottom) {
holder.footView.setVisibility(View.VISIBLE);
if (VisitFragment.isLoadBottom) {
holder.tvBottom.setVisibility(View.VISIBLE);
holder.pb.setVisibility(View.GONE);
} else {
holder.tvBottom.setVisibility(View.GONE);
holder.pb.setVisibility(View.VISIBLE);
}
}else {
holder.footView.setVisibility(View.GONE);
}
}
}
@Override
public int getItemViewType(int position) {
if (position == getItemCount() - 1) {
return FOOT_VIEW;
}
return NORMAL_VIEW;
}
@Override
public int getItemCount() {
return list.size() + 1;
}
public interface OnItemClickListener {
void onItemClick(View view, int position);
}
@Override
public void onClick(View v) {
if (itemClick != null) {
if (v.getTag() == null) {
return;
} else
itemClick.onItemClick(v, (int) v.getTag());
}
}
public void setOnItemClickListener(OnItemClickListener listener) {
this.itemClick = listener;
}
}
3. item_visit.xml的布局里的style我就不做公布了,其实这个item都是可以换成自己的item的。
<?xml version="1.0" encoding="utf-8"?>
<android.support.percent.PercentFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
style="@style/style_MW"
android:background="@color/color_white"
android:orientation="vertical">
<!--<android.support.v7.widget.CardView-->
<!--style="@style/style_card_home"-->
<!--app:cardCornerRadius="@dimen/size_5">-->
<RelativeLayout
style="@style/style_MW"
android:background="@color/color_white"
android:padding="@dimen/size_10">
<ImageView
android:id="@+id/iv_item_visit_head"
android:layout_width="@dimen/size_40"
android:layout_height="@dimen/size_40"
android:src="@mipmap/ic_launcher_round" />
<LinearLayout
style="@style/style_MW"
android:layout_marginStart="@dimen/size_20"
android:layout_toRightOf="@id/iv_item_visit_head"
android:orientation="vertical">
<TextView
android:id="@+id/tv_item_visit_title"
style="@style/style_WW"
android:textColor="@color/color_jcdecaux"
android:textSize="@dimen/size_16_text" />
<LinearLayout
style="@style/style_MW"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:layout_width="@dimen/size_10"
android:layout_height="@dimen/size_10"
android:src="@drawable/iv_brand" />
<TextView
android:id="@+id/tv_item_visit_brand"
style="@style/style_text_visit"
android:layout_marginStart="@dimen/size_5" />
</LinearLayout>
<LinearLayout
style="@style/style_MW"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:layout_width="@dimen/size_12"
android:layout_height="@dimen/size_12"
android:src="@drawable/iv_position" />
<TextView
android:id="@+id/tv_item_visit_address"
style="@style/style_text_visit"
android:layout_marginStart="@dimen/size_5" />
</LinearLayout>
<LinearLayout
style="@style/style_MW"
android:layout_marginTop="@dimen/size_10"
android:background="@color/color_grey"
android:orientation="vertical"
android:padding="@dimen/size_2">
<RelativeLayout style="@style/style_MW">
<TextView
android:id="@+id/tv_item_visit_title1"
style="@style/style_text_visit" />
<TextView
android:id="@+id/tv_item_visit_date1"
style="@style/style_text_visit"
android:layout_alignParentEnd="true" />
</RelativeLayout>
<TextView
android:id="@+id/tv_item_visit_content1"
style="@style/style_text_visit" />
<TextView
android:id="@+id/tv_item_visit_detail1"
style="@style/style_text_visit"
android:textColor="@color/color_jcdecaux"
android:textSize="@dimen/size_12_text" />
</LinearLayout>
<View
style="@style/style_apart_me_match"
android:background="@color/color_white" />
<LinearLayout
android:id="@+id/ll_item_visit_content2"
style="@style/style_MW"
android:background="@color/color_grey"
android:orientation="vertical"
android:padding="@dimen/size_2">
<RelativeLayout style="@style/style_MW">
<TextView
android:id="@+id/tv_item_visit_title2"
style="@style/style_text_visit" />
<TextView
android:id="@+id/tv_item_visit_date2"
style="@style/style_text_visit"
android:layout_alignParentEnd="true" />
</RelativeLayout>
<TextView
android:id="@+id/tv_item_visit_content2"
style="@style/style_text_visit" />
<TextView
android:id="@+id/tv_item_visit_detail2"
style="@style/style_text_visit"
android:textColor="@color/color_jcdecaux"
android:textSize="@dimen/size_12_text" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>
<View style="@style/style_line_horizontal" />
<!--</android.support.v7.widget.CardView>-->
</android.support.percent.PercentFrameLayout>
4. layout_recyclerview_bottom.xml里的TextView和ProgressBar放到了相对布局里,作为重叠布局来用。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rl_layout_recyclerview_bottom"
style="@style/style_MW"
android:background="@color/bg_page"
android:orientation="vertical">
<RelativeLayout style="@style/style_MW">
<TextView
android:id="@+id/tv_layout_recyclerview_bottom"
style="@style/style_text"
android:layout_width="match_parent"
android:layout_height="@dimen/size_40"
android:layout_alignParentBottom="true"
android:gravity="center"
android:text="@string/text_baseline"
android:textColor="@color/color_333" />
<ProgressBar
android:id="@+id/pb_layout_recyclerview_bottom"
android:layout_width="match_parent"
android:layout_height="@dimen/size_30"
android:layout_alignParentBottom="true"
android:indeterminateTint="@color/color_jcdecaux"
android:indeterminateTintMode="src_atop" />
</RelativeLayout>
<View style="@style/style_line_horizontal" />
</LinearLayout>
好了,上拉加载和下拉刷新就这么简单得实现了,有木有简单到你?
公司内部代码仅公开部分代码,不做代码共享哦!其实啊,明白了这个思路,你就已经能实现了。
哈哈,加油!