[Android] Android 支持下拉刷新、上拉加载更多 的 XRecyclerview

XRecyclerView一个实现了下拉刷新,滚动到底部加载更多以及添加header功能的的RecyclerView。使用方式和RecyclerView完全一致,不需要额外的layout,不需要写特殊的adater。 加载效果内置了AVLoadingIndicatorView上的所有效果,可以根据需要指定。

效果演示如下:

 

插件官网地址:

https://github.com/XRecyclerView/XRecyclerView

一、添加依赖

compile 'com.jcodecraeer:xrecyclerview:1.5.9'

 

 

二、布局文件

1) 显示的Fragment或Activity布局文件 (我这里是在Fragment文件中)

fragment_news_list.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <com.jcodecraeer.xrecyclerview.XRecyclerView
        android:id="@+id/x_recycle_list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</LinearLayout>

 

2)每个Item布局文件 

item_news_list_style_1.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="120dp"
        android:orientation="horizontal"
        android:padding="16dp">

        <RelativeLayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:orientation="vertical">

            <TextView
                android:id="@+id/tv_title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center|left"
                android:text="标标标题标题标题标题标题题标题标题标题标题题标题标题标题标题标题"
                android:textColor="@color/black"
                android:textSize="16sp" />

            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_alignParentBottom="true"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true"
                android:layout_gravity="bottom"
                android:gravity="center_vertical"
                android:orientation="horizontal">

                <TextView
                    android:id="@+id/tv_cate_name"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="今日新闻"
                    android:textSize="12sp" />

                <TextView
                    android:id="@+id/tv_read_num"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentTop="true"
                    android:layout_marginLeft="10dp"
                    android:layout_toRightOf="@+id/tv_cate_name"
                    android:text="100"
                    android:textSize="12sp" />

                <ImageView
                    android:id="@+id/iv_delete"
                    android:layout_width="20dp"
                    android:layout_height="12dp"
                    android:layout_alignParentEnd="true"
                    android:layout_alignParentRight="true"
                    android:layout_centerVertical="true"
                    android:layout_gravity="right"
                    android:background="@mipmap/ic_article_delete" />

                <TextView
                    android:id="@+id/tv_time"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginRight="5dp"
                    android:layout_toLeftOf="@id/iv_delete"
                    android:text="刚刚"
                    android:textSize="12sp" />
            </RelativeLayout>
        </RelativeLayout>

        <ImageView
            android:id="@+id/iv_main_img"
            android:layout_width="130dp"
            android:layout_height="match_parent"
            android:layout_gravity="center"
            android:layout_marginLeft="10dp"
            android:src="@mipmap/img_show" />
    </LinearLayout>

    <View
        android:layout_width="match_parent"
        android:layout_height="0.5dp"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:background="@color/tv_line" />

</LinearLayout>

 

三、Adapter类实现

NewsListRecycleAdapter.java   (与普通的RecycleListView 的Adapter 类似)

package com.jack.appnews.adapter;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.jack.appnews.R;
import com.jack.appnews.bean.ItemNewsBean;
import com.jcodecraeer.xrecyclerview.XRecyclerView;

import java.util.List;

import butterknife.BindView;
import butterknife.ButterKnife;

public class NewsListRecycleAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private Context context;
    private List<ItemNewsBean> items;
    private ClickListener clickListener;

    public NewsListRecycleAdapter(Context context, List<ItemNewsBean> items) {
        this.context = context;
        this.items = items;
    }

    public interface ClickListener {
        void onItemClick(View v, int position);
    }

    public void setOnItemClickListener(ClickListener clickListener) {
        this.clickListener = clickListener;
    }

    @Override
    public XRecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view;
        RecyclerView.ViewHolder viewHolder = null;

        switch (viewType) {
            case 1:
                view = LayoutInflater.from(parent.getContext()).inflate(
                        R.layout.item_news_list_style_1, parent, false);
                viewHolder = new ViewHolderOne(view);
                break;
        }
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(final XRecyclerView.ViewHolder holder, int position) {
        ItemNewsBean newsBean = items.get(position);
        switch (getItemViewType(position)) {
            case 1: //1张图 情况
                ViewHolderOne ViewHolderOne = (ViewHolderOne) holder;
                ViewHolderOne.tvTitle.setText(newsBean.getNews_title());
                ViewHolderOne.tvCateName.setText(newsBean.getSource_name());

                if (newsBean.getImg_list() != null && newsBean.getImg_list().size() > 0) {
                    Glide.with(context)
                            .load(newsBean.getImg_list().get(0))
                            .error(R.mipmap.ic_article_delete)
                            .diskCacheStrategy(DiskCacheStrategy.ALL)
                            .into(ViewHolderOne.ivImage);
                }

                break;
        }

        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int pos = holder.getLayoutPosition();
                clickListener.onItemClick(holder.itemView, pos);
            }
        });
    }

    @Override
    public int getItemViewType(int position) {
        return items.get(position).getContent_type();
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public int getItemCount() {
        return items.size();
    }

    //1张图
    public static class ViewHolderOne extends RecyclerView.ViewHolder {
        @BindView(R.id.tv_title)
        TextView tvTitle;
        @BindView(R.id.tv_cate_name)
        TextView tvCateName;
        @BindView(R.id.iv_main_img)
        ImageView ivImage;

        public ViewHolderOne(View view) {
            super(view);
            ButterKnife.bind(this, view);
        }

    }
}

 

 

四、主界面文件调用

NewsListFragment.java   (为方便测试,将数据都写死在文件中)

package com.jack.appnews.ui.fragment;

import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.v7.widget.LinearLayoutManager;
import android.view.View;
import android.widget.Toast;

import com.jack.appnews.R;
import com.jack.appnews.adapter.NewsListRecycleAdapter;
import com.jack.appnews.bean.ItemNewsBean;
import com.jack.appnews.ui.BaseFragment;
import com.jcodecraeer.xrecyclerview.ProgressStyle;
import com.jcodecraeer.xrecyclerview.XRecyclerView;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import butterknife.BindView;

/**
 * 新闻列表
 */
public class NewsListFragment extends BaseFragment {
    @BindView(R.id.x_recycle_list)
    XRecyclerView mRecyclerView;

    private NewsListRecycleAdapter mAdapter;
    private List<ItemNewsBean> mList = new ArrayList<>();
    private List<String> imgList1 = new ArrayList<>();
    private List<String> imgList2 = new ArrayList<>();
    private int times = 0;

    @Override
    protected int inflateLayoutId() {
        return R.layout.fragment_news_list;
    }

    @Override
    protected void prepare() {
        genImgList();
    }

    protected void initViews() {
        //1)初始化RecyclerView设置
        mRecyclerView.setPullRefreshEnabled(true);
        mRecyclerView.setLoadingMoreEnabled(true);
        mRecyclerView.setRefreshProgressStyle(ProgressStyle.BallSpinFadeLoader);
        mRecyclerView.setLoadingMoreProgressStyle(ProgressStyle.BallClipRotate);

        //2)添加布局管理器
        LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        mRecyclerView.setLayoutManager(layoutManager);

        //3)配置Adapter
        mList = genData();
        mAdapter = new NewsListRecycleAdapter(getContext(), mList);
        mRecyclerView.setAdapter(mAdapter);

        //4) 监听 点击,注意是监听 mAdapter ,而不是 mRecyclerView
        mAdapter.setOnItemClickListener(new NewsListRecycleAdapter.ClickListener() {
            @Override
            public void onItemClick(View v, int position) {
                Toast.makeText(getContext(), "click, pos:" + position, Toast.LENGTH_LONG).show();
            }
        });

        //5)实现 下拉刷新和加载更多 接口
        mRecyclerView.setLoadingListener(new XRecyclerView.LoadingListener() {
            @Override
            public void onRefresh() {
                times = 0;
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        mList.clear(); //先要清掉数据

                        List<ItemNewsBean> list = genRefreshData();
                        mList.addAll(list); //再将数据插入到前面

                        mAdapter.notifyDataSetChanged();

                        mRecyclerView.refreshComplete(); //下拉刷新完成
                        Toast.makeText(getContext(), "刷新完成,新加" + list.size() + "条新闻", Toast.LENGTH_SHORT).show();
                    }
                }, 1000);

            }

            @Override
            public void onLoadMore() {
                if (times < 20) {//加载20次后,就不再加载更多
                    new Handler().postDelayed(new Runnable() {
                        public void run() {
                            List<ItemNewsBean> list = genLoadMoreData();
                            mList.addAll(list); //直接将数据追加到后面
                            Toast.makeText(getContext(), "加载完成,新加" + list.size() + "条新闻", Toast.LENGTH_SHORT).show();

                            mRecyclerView.loadMoreComplete();
                            mAdapter.notifyDataSetChanged();
                        }
                    }, 1000);
                } else {
                    new Handler().postDelayed(new Runnable() {
                        public void run() {
                            List<ItemNewsBean> list = genLoadMoreData();
                            mList.addAll(list); //将数据追加到后面

                            mAdapter.notifyDataSetChanged();
                            mRecyclerView.setNoMore(true);
                        }
                    }, 1000);
                }
                times++;
            }
        });
    }

    /**
     * 初始化需要显示的图片
     */
    private void genImgList() {
        imgList1.add("http://p3-tt.bytecdn.cn/list/300x196/pgc-image/ROLsHtn2l4vdxK");
        imgList2.add("http://p3-tt.bytecdn.cn/list/300x196/1f50e0009802d39b66b76");
    }

    @NonNull
    /**
     * 生成数据实例
     */
    private List<ItemNewsBean> genData() {
        List<ItemNewsBean> mList = new ArrayList<>();
        mList.add(new ItemNewsBean("奔驰之后是宝马,汽车“召回”和“不召回”哪个更可怕?", "央视网", imgList1, 1));
        mList.add(new ItemNewsBean("全台所有村长遭恐吓:访大陆如签协议,将被罚50万", "大连阳光新闻网", 1));
        mList.add(new ItemNewsBean("中国驻斯里兰卡大使馆:中国公民确认死亡人数修正为1人", "一点咨询新闻", 1));
        mList.add(new ItemNewsBean("特斯拉回应车辆自燃:已联络车主 最大努力协助善后", "一起来育儿", imgList2, 1));
        mList.add(new ItemNewsBean("中国驻斯里兰卡大使馆:中国公民确认死亡人数修正为1人", "一点咨询新闻", 1));
        mList.add(new ItemNewsBean("住建部预警房价地价波动较大城市 部分区域楼市调控或升级", "一点咨询新闻", 1));
        mList.add(new ItemNewsBean("中国驻斯里兰卡大使馆:中国公民确认死亡人数修正为1人", "一点咨询新闻", 1));
        mList.add(new ItemNewsBean("全台所有村长遭恐吓:访大陆如签协议,将被罚50万", "大连阳光新闻网", 1));
        mList.add(new ItemNewsBean("特斯拉回应车辆自燃:已联络车主 最大努力协助善后", "一起来育儿", imgList2, 1));

        Collections.shuffle(mList);//打乱顺序输出,为了美观
        return mList;
    }

    private List<ItemNewsBean> genRefreshData() {
        List<ItemNewsBean> mList = new ArrayList<>();
        mList.add(new ItemNewsBean("刷新数据:中石化新任总经理,有颗小行星以他命名", "腾讯新闻网", imgList1, 1));
        mList.add(new ItemNewsBean("刷新数据:互联护苗·2019活动启动", "一点咨询新闻", imgList2, 1));
        mList.add(new ItemNewsBean("刷新数据:全台所有村长遭恐吓:访大陆如签协议,将被罚50万", "大连阳光新闻网", 1));
        mList.add(new ItemNewsBean("刷新数据:中国驻斯里兰卡大使馆:中国公民确认死亡人数修正为1人", "一点咨询新闻", 1));
        mList.add(new ItemNewsBean("刷新数据:住建部预警房价地价波动较大城市 部分区域楼市调控或升级", "一点咨询新闻", 1));
        mList.add(new ItemNewsBean("刷新数据:中国驻斯里兰卡大使馆:中国公民确认死亡人数修正为1人", "一点咨询新闻", 1));
        mList.add(new ItemNewsBean("刷新数据:住建部之所以对部分热点城市发出预警,意在对市场预期进行适度引导", "一点咨询新闻", 1));
        mList.add(new ItemNewsBean("刷新数据:其他政策的调整对楼市影响将相对有限", "一点咨询新闻", 1));

        Collections.shuffle(mList);//打乱顺序输出,为了美观
        return mList;
    }

    private List<ItemNewsBean> genLoadMoreData() {
        List<ItemNewsBean> mList = new ArrayList<>();
        mList.add(new ItemNewsBean("加载数据:清华大学:博士生不再强制要求在学期间发表论文", "百度新闻网", imgList1, 1));
        mList.add(new ItemNewsBean("加载数据:这几位部长去了同一个地方,事关高层部署", "一点咨询新闻", 1));

        Collections.shuffle(mList);//打乱顺序输出,为了美观
        return mList;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mRecyclerView != null) {
            mRecyclerView.destroy();
            mRecyclerView = null;
        }
    }
}

 

 

基本核心代码,都在上述文件中 红色字体 标明!

 

五、最后附上Github 代码地址:

https://github.com/wukong1688/Android-BaseTabHost

 

这是我用FragmentTabHost + ViewPager + XRecycleList   实现的  标签切换 + 列表上滑加载+列表下滑刷新

其中 标签切换 可参考上一篇文章:

Android 使用 FragmentTabHost + Fragment 实现 微信 底部菜单

 

本博客地址: wukong1688

本文原文地址:https://www.cnblogs.com/wukong1688/p/10754200.html

转载请著名出处!谢谢~~

posted @ 2019-04-23 05:48  wukong1688  阅读(2112)  评论(0编辑  收藏  举报