Android 推荐几款好用的开源作品(二)之万能RecyclerView适配器

前言:RecyclerView出现已经有一段时间了,我们肯定不陌生了,可以通过导入support-v7对其进行使用。

根据官方的文档,该控件用于在有限的窗口中展示大量数据集,其实有了它就可以替代ListView、GridView了。

了解RecyclerView架构,可以高度的解耦,异常的灵活,通过设置它提供的不同LayoutManager,ItemDecoration , ItemAnimator可以实现的想要的效果。

1、首先介绍几种LayoutManager

LinearLayoutManager mManager = new LinearLayoutManager(mContent);
LinearLayoutManager mManager = new LinearLayoutManager(mContent, LinearLayoutManager.VERTICAL, false);//垂直布局,true表示左右翻转,false不翻转
GridLayoutManager mManager = new GridLayoutManager(mContent,3);
GridLayoutManager mManager = new GridLayoutManager(mContent,3,LinearLayoutManager.HORIZONTAL,false);//每行3列,水平,true表示左右翻转,false不翻转
mRecyclerView.setLayoutManager(mManager);</span>

2、RecycleView简单使用

//初始化控件
mRecyclerView = findView(R.id.id_recyclerview);
//设置布局管理器
mManager = new LinearLayoutManager(mContent);
mRecyclerView.setLayoutManager(mManager);
//设置adapter
mRecyclerView.setAdapter(mAdapter)
//设置Item增加、移除动画
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
//添加分割线
mRecyclerView.addItemDecoration(new DividerItemDecoration(
                getActivity(), DividerItemDecoration.HORIZONTAL_LIST));

3、接下来介绍的就是RecyclerView的适配器了,同样,RecyclerView和ListView,GridView一样需要adapter来填充数据,同样,自定义一个adapter需要继承RecyclerView.Adapter,代码需要实现几个父类方法onCreateViewHolder,onBindViewHolder,getItemCount(),根据名字就能知道:

(1)onCreateViewHolder:主要返回的是拿到布局,进而返回ViewHolder

return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.list_cell,null));

(2)onBindViewHolder:拿到ViewHolder中的控件对其赋值操作

(3)getItemCount():返回数组的size()

public class MyAdapter extends RecyclerView.Adapter {

    class ViewHolder extends RecyclerView.ViewHolder {

        TextView tvTitle,tvContent;

        public ViewHolder(View itemView) {
            super(itemView);
            tvTitle = (TextView) itemView.findViewById(R.id.tv_title);
            tvContent = (TextView) itemView.findViewById(R.id.tv_content);
        }

    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.list_cell,null));
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        ViewHolder vh = (ViewHolder) holder;
        CellData cd = data[position];
        vh.tvTitle.setText(cd.title);
        vh.tvContent.setText(cd.content);
    }

    @Override
    public int getItemCount() {
        return data.length;
    }

    private CellData[] data = new CellData[]{new CellData("recycleview","学习recycleview"),new CellData("天气","今天天气不错"),new CellData("recycleview","学习recycleview"),new CellData("天气","今天天气不错"),new CellData("recycleview","学习recycleview"),new CellData("天气","今天天气不错"),new CellData("recycleview","学习recycleview"),new CellData("天气","今天天气不错"),new CellData("recycleview","学习recycleview"),new CellData("天气","今天天气不错"),new CellData("recycleview","学习recycleview"),new CellData("天气","今天天气不错"),new CellData("recycleview","学习recycleview"),new CellData("天气","今天天气不错"),new CellData("recycleview","学习recycleview"),new CellData("天气","今天天气不错"),new CellData("recycleview","学习recycleview"),new CellData("天气","今天天气不错"),new CellData("recycleview","学习recycleview"),new CellData("天气","今天天气不错"),new CellData("recycleview","学习recycleview"),new CellData("天气","今天天气不错"),new CellData("recycleview","学习recycleview"),new CellData("天气","今天天气不错"),new CellData("recycleview","学习recycleview"),new CellData("天气","今天天气不错"),new CellData("recycleview","学习recycleview"),new CellData("天气","今天天气不错"),new CellData("recycleview","学习recycleview"),new CellData("天气","今天天气不错"),new CellData("recycleview","学习recycleview"),new CellData("天气","今天天气不错"),new CellData("recycleview","学习recycleview"),new CellData("天气","今天天气不错"),new CellData("recycleview","学习recycleview"),new CellData("天气","今天天气不错"),new CellData("recycleview","学习recycleview"),new CellData("天气","今天天气不错"),new CellData("recycleview","学习recycleview"),new CellData("天气","今天天气不错"),new CellData("recycleview","学习recycleview"),new CellData("天气","今天天气不错"),new CellData("recycleview","学习recycleview"),new CellData("天气","今天天气不错"),new CellData("recycleview","学习recycleview"),new CellData("天气","今天天气不错"),new CellData("recycleview","学习recycleview"),new CellData("天气","今天天气不错"),new CellData("recycleview","学习recycleview"),new CellData("天气","今天天气不错"),new CellData("recycleview","学习recycleview"),new CellData("天气","今天天气不错"),new CellData("recycleview","学习recycleview"),new CellData("天气","今天天气不错")};
}

4、效果图,虽然很难看,但是是基本的实现方式。

可见,RecyclerView和传统的ListView,GridView使用的流程是一样的,但是由于RecyclerView的高定制性,使用者越来越多,已经有大部分的开发者放弃使用ListView和GridView了。想要用好RecyclerView也不难,关键就在于Adapter的书写上,接下来介绍一个非常好用的RecyclerView万能适配器(BaseRecyclerViewAdapterHelper),前几天接触到的,感觉十分好用,所包含的功能有以下几个(官网介绍):

  • 优化Adapter代码(减少百分之70%代码)
  • 添加点击item点击、长按事件、以及item子控件的点击事件
  • 添加加载动画(一行代码轻松切换5种默认动画)
  • 添加头部、尾部、下拉刷新、上拉加载(感觉又回到ListView时代)
  • 设置自定义的加载更多布局
  • 添加分组(随心定义分组头部)
  • 自定义不同的item类型(简单配置、无需重写额外方法)
  • 设置空布局(比Listview的setEmptyView还要好用!)
  • 添加拖拽item

1、添加item点击、长按事件

mQuickAdapter.setOnRecyclerViewItemClickListener();
mQuickAdapter.setOnRecyclerViewItemLongClickListener();

2、新增添加子布局多个控件的点击事件

Adapter

protected void convert(BaseViewHolder helper, Status item) {
    helper.setOnClickListener(R.id.tweetAvatar, new OnItemChildClickListener())
      .setOnClickListener(R.id.tweetName, new OnItemChildClickListener());
      }

Activity

mQuickAdapter.setOnRecyclerViewItemChildClickListener(new BaseQuickAdapter.OnRecyclerViewItemChildClickListener() {
            @Override
            public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) {
                String content = null;
                Status status = (Status) adapter.getItem(position);
                switch (view.getId()) {
                    case R.id.tweetAvatar:
                        content = "img:" + status.getUserAvatar();
                        break;
                    case R.id.tweetName:
                        content = "name:" + status.getUserName();
                        break;
                }
                Toast.makeText(AnimationUseActivity.this, content, Toast.LENGTH_LONG).show();
            }
        });

3、添加动画

// 一行代码搞定(默认为渐显效果)
quickAdapter.openLoadAnimation();
// 默认提供5种方法(渐显、缩放、从下到上,从左到右、从右到左)
quickAdapter.openLoadAnimation(BaseQuickAdapter.ALPHAIN);
// 自定义动画如此轻松
quickAdapter.openLoadAnimation(new BaseAnimation() {
                            @Override
                            public Animator[] getAnimators(View view) {
                                return new Animator[]{
                                        ObjectAnimator.ofFloat(view, "scaleY", 1, 1.1f, 1),
                                        ObjectAnimator.ofFloat(view, "scaleX", 1, 1.1f, 1)
                                };
                            }
                        });

4、添加头部和尾部

mQuickAdapter.addHeaderView(getView());
mQuickAdapter.addFooterView(getView());

5、上拉加载更多

mQuickAdapter.openLoadMore(PAGE_SIZE, true);//必须设置pageSize,否则上拉不会加载,pageSize一般为每次请求需要加载的数据条数
mQuickAdapter.setOnLoadMoreListener(new BaseQuickAdapter.RequestLoadMoreListener() {
            @Override
            public void onLoadMoreRequested() {
                mRecyclerView.post(new Runnable() {
                    @Override
                    public void run() {
                        if (mCurrentCounter >= TOTAL_COUNTER) {
                            mQuickAdapter.notifyDataChangedAfterLoadMore(false);
                        } else {
                            mQuickAdapter.notifyDataChangedAfterLoadMore(DataServer.getSampleData(PAGE_SIZE), true);
                            mCurrentCounter = mQuickAdapter.getItemCount();
                        }
                    }

                });
            }
        });

可以通过mQuickAdapter.setLoadingView(customView);自定义加载更多的布局

6、使用分组

public class SectionAdapter extends BaseSectionQuickAdapter<MySection> {
     public SectionAdapter(int layoutResId, int sectionHeadResId, List data) {
        super(layoutResId, sectionHeadResId, data);
    }
    @Override
    protected void convert(BaseViewHolder helper, MySection item) {
        helper.setImageUrl(R.id.iv, (String) item.t);
    }
    @Override
    protected void convertHead(BaseViewHolder helper,final MySection item) {
        helper.setText(R.id.header, item.header);
        else
        helper.setOnClickListener(R.id.more, new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(context,item.header+"more..",Toast.LENGTH_LONG).show();
            }
        });
    }

7、添加多种类型Item

public class MultipleItemQuickAdapter extends BaseMultiItemQuickAdapter<MultipleItem> {

    public MultipleItemQuickAdapter(List data) {
        super(data);
        addItemType(MultipleItem.TEXT, R.layout.text_view);
        addItemType(MultipleItem.IMG, R.layout.image_view);
    }

    @Override
    protected void convert(BaseViewHolder helper, MultipleItem item) {
        switch (helper.getItemViewType()) {
            case MultipleItem.TEXT:
                helper.setImageUrl(R.id.tv, item.getContent());
                break;
            case MultipleItem.IMG:
                helper.setImageUrl(R.id.iv, item.getContent());
                break;
        }
    }

}

8、使用setEmptyView

mQuickAdapter.setEmptyView(getView());

9、使用拖拽与滑动删除

OnItemDragListener onItemDragListener = new OnItemDragListener() {
    @Override
    public void onItemDragStart(RecyclerView.ViewHolder viewHolder, int pos){}
    @Override
    public void onItemDragMoving(RecyclerView.ViewHolder source, int from, RecyclerView.ViewHolder target, int to) {}
    @Override
    public void onItemDragEnd(RecyclerView.ViewHolder viewHolder, int pos) {}
}

OnItemSwipeListener onItemSwipeListener = new OnItemSwipeListener() {
    @Override
    public void onItemSwipeStart(RecyclerView.ViewHolder viewHolder, int pos) {}
    @Override
    public void clearView(RecyclerView.ViewHolder viewHolder, int pos) {}
    @Override
    public void onItemSwiped(RecyclerView.ViewHolder viewHolder, int pos) {}
};

ItemDragAndSwipeCallback itemDragAndSwipeCallback = new ItemDragAndSwipeCallback(mAdapter);
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(itemDragAndSwipeCallback);
itemTouchHelper.attachToRecyclerView(mRecyclerView);

// 开启拖拽
mAdapter.enableDragItem(itemTouchHelper, R.id.textView, true);
mAdapter.setOnItemDragListener(onItemDragListener);

// 开启滑动删除
mAdapter.enableSwipeItem();
mAdapter.setOnItemSwipeListener(onItemSwipeListener);

感觉每一个功能都很实用,目前也在努力在项目中进行测试使用。

最常用的莫过于下拉刷新,上拉加载的,基本每个页面都会用到刷新,需要分页的页面还会用到加载。曾经搜了下网上的相关于这方面的资源,感觉基本没有将RecyclerView配合SwipeRefreshLayout做到很好能刷新和加载的。其他的都是自定义的ListView 和GridView实现的刷新和加载,由于不太想用ListView了,所以就换成了RecyclerView,闲淡少扯,实战继续。

先上图:

需求分析:通过接口返回的数据需要进行分页
{
  "code": 1,
  "pageCount": 33,
  "list": [
    {
      "province": "XX省",
      "city": "XX市",
      "address": "XX区XX路",
      "scan_time": "2016/7/9 10:30:44",
      "product_id": "1",
      "product_name": "MOOKA4K电视U55H3",
      "product_small_image": "http://cdn02.ehaier.com/product/561f4f031671c47b688b4851_80_80.jpg",
      "eancode": "6925876304318",
      "sn": "DH1TV0A0701HUF530144"
    }
  ]
}

Adapter

public class QuickAdapter extends BaseQuickAdapter<ScanRecordRowEntity> {

    private ImageLoader imageLoader = ImageLoader.getInstance();

    public QuickAdapter(List<ScanRecordRowEntity> data) {
        super(data);
    }

    public QuickAdapter(int layoutResId, List<ScanRecordRowEntity> data) {
        super(layoutResId, data);
    }

    @Override
    protected void convert(BaseViewHolder helper, ScanRecordRowEntity item) {
        helper.setText(R.id.tv_product_name, item.getProduct_name())
                .setText(R.id.tv_time, item.getScan_time())
                .setText(R.id.tv_place, item.getProvince() + item.getCity());

//        imageLoader.displayImage(item.getProduct_small_image(), (ImageView) helper.getView(R.id.img_product_logo), ImageLoaderUtils.getDefaultOptions());

        Glide.with(mContext)
                .load(item.getProduct_small_image())
                .fitCenter()
                .placeholder(R.drawable.ic_product_default)
                .crossFade()
                .into((ImageView) helper.getView(R.id.img_product_logo));
    }

}

Activity

public class ScanRecordTestActivity extends BaseActivity implements SwipeRefreshLayout.OnRefreshListener, BaseQuickAdapter.RequestLoadMoreListener {

    private List<ScanRecordRowEntity> list = new ArrayList<>();
    private String encode;
    private SwipeRefreshLayout mSwipeRefreshLayout;
    private RecyclerView mRecyclerView;
    private QuickAdapter mQuickAdapter;
    private int pageCount = 1;//分页返回总页数
    private int page = 1;//当前请求页为第一页
    private int pageSize = 10;//每次请求10条记录

    @Override
    protected void initView() {
        setContentView(R.layout.activity_scan_record_test);
        setBack();
        setTitle("扫描记录");
        mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.id_swiperefresh);
        RefreshUtil.setSwipeRefreshColor(mSwipeRefreshLayout);//设置刷新框颜色
        mRecyclerView = (RecyclerView) findViewById(R.id.id_recycleview);
        mSwipeRefreshLayout.setOnRefreshListener(this);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        initAdapter();
        mRecyclerView.setAdapter(mQuickAdapter);

    }

    private void initAdapter() {
        mQuickAdapter = new QuickAdapter(R.layout.item_scan_record, list);
        mQuickAdapter.openLoadAnimation();
        mRecyclerView.setAdapter(mQuickAdapter);
        mQuickAdapter.setOnLoadMoreListener(this);
        mQuickAdapter.setOnRecyclerViewItemClickListener(new BaseQuickAdapter.OnRecyclerViewItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {
                Toasters(Integer.toString(position));
            }
        });
    }

    @Override
    protected void initData() {
        encode = getIntent().getStringExtra("encode");
        if (NetUtil.isNetConnected(mContext)) {
            RefreshUtil.setSwipeRefreshLoadingState(mSwipeRefreshLayout);//设置首次加载数据时显示加载框
            getRecord();
        } else {
            Toasters("无网络连接!");
        }
    }

    @Override
    protected void setOnClickEvent() {
    }

    private void getRecord() {
        String url = Constant.GET_SCAN_RECORD + encode + "?rows=" + pageSize + "&page=" + page + "&type";
        webHttpconnection.getValue(url, 1);
    }

    private void LoadMore(final int page) {
        String url = Constant.GET_SCAN_RECORD + encode + "?rows=" + pageSize + "&page=" + page + "&type";
        webHttpconnection.getValue(url, 2);
    }

    @Override
    public void onRefresh() {
        page = 1;
        getRecord();
    }

    @Override
    public void onLoadMoreRequested() {
        if (page < pageCount) {
            page = page + 1;
            LoadMore(page);
        }
    }

    @Override
    public void requestJsonOnSucceed(String json, int msgFlag) {
        super.requestJsonOnSucceed(json, msgFlag);
        ScanRecordEntity entity;
        switch (msgFlag) {
            case 1:
                RefreshUtil.setSwipeRefreshLoadedState(mSwipeRefreshLayout);
                entity = JSON.parseObject(json, ScanRecordEntity.class);
                if (1 == entity.getCode() && null != entity.getList()) {
                    pageCount = entity.getPageCount();
                    mQuickAdapter.setNewData(entity.getList());
                    if (pageCount > 1) {
                        mQuickAdapter.openLoadMore(pageSize, true);
                        mQuickAdapter.notifyDataChangedAfterLoadMore(true);
                    }
                } else {
                    Toasters("无扫描记录!");
                }
                break;
            case 2:
                entity = JSON.parseObject(json, ScanRecordEntity.class);
                if (1 == entity.getCode() && null != entity.getList()) {
                    mQuickAdapter.addData(entity.getList());
                }
                if (pageCount == page) {
                    mQuickAdapter.notifyDataChangedAfterLoadMore(false);
                    View view = getLayoutInflater().inflate(R.layout.not_loading, (ViewGroup) mRecyclerView.getParent(), false);
                    mQuickAdapter.addFooterView(view);
                } else {
                    mQuickAdapter.notifyDataChangedAfterLoadMore(true);
                }
                break;
        }
    }

    @Override
    public void requestJsonOnError(int msgFlag) {
        super.requestJsonOnError(msgFlag);
        Toasters("网络不可用");
    }

BaseRecyclerViewAdapterHelper开源地址:https://github.com/CymChad/BaseRecyclerViewAdapterHelper,后续还会进行研究。

时间: 2024-10-03 22:55:43

Android 推荐几款好用的开源作品(二)之万能RecyclerView适配器的相关文章

推荐一款基于XNA的开源游戏引擎《Engine Nine》

一.前沿导读 XNA是微软基于.Net部署的下一代3D/2D游戏开发框架,其实XNA严格来说类似下一代的DirectX,当然不是说XNA会取代DirectX,但是基于XNA我们对于面向XBOX360,WP等系列其他平台的移植成本非常的低(据说基于MONO在linux下XNA也可以运行3D DEMO,有试过的请点意见). 但是基于XNA的复杂程度我们自然也是可想而知的,所以在这里推荐第一款基于XNA的游戏引擎,Engine Nine. 二.Engine Nine介绍 Engine Nine是一款基

推荐两款Windows下的开源调试器

在软件开发过程中,调试器可以说是一个得力助手,善用它你就可以快速定位bug并消灭之. 想想以前不会使用调试器功能的时候只靠输出数据来差错的方式,真是效率太低了. 如果你对调试器的运行原理好奇,学习开源软件是最好的途径.当然必备的入门书籍还是有必要的,如张银奎先生的<软件调试>一书就是本经典书籍. 言归正传,下面向大家推荐两款值得学习用的调试器.首先向大家推荐的是Nanomite,这是我在github上最早接触的一款开源调试器,支持x86/x64调试,可惜现在已经不更新了,但是基本功能都已经实现

推荐10款流行的java开源的网络爬虫

1:JAVA爬虫WebCollector(Star:1345) 爬虫简介: WebCollector是一个无须配置.便于二次开发的JAVA爬虫框架(内核),它提供精简的的API,只需少量代码即可实现一个功能强大的爬虫.WebCollector-Hadoop是WebCollector的Hadoop版本,支持分布式爬取. 爬虫内核: WebCollector致... 2:开源通用爬虫框架YayCrawler(Star:91) YayCrawler是一个基于WebMagic开发的分布式通用爬虫框架,开

推荐一款Linux下的开源编辑器

Sublime编辑器,下载地址.下载后解压,解压到家目录下,为解压后的文件夹里的可执行文件添加环境变量, vim ~/.bashrc 打开配置环境变量的文件,在最后一行添加export PATH="~/sublime_text_3:$PATH", 为了使修改后的环境变量配置文件生效,执行source ~/.bashrc ,这样每次打开终端在里面输入sublime_text 就可以打开sublime编辑器,为了更方便的打开sublime编辑器,我们可以为可执行文件sublime_text

推荐 11 款 React Native 开源移动 UI 组件

推荐 11 款 React Native 开源移动 UI 组件 oschina 发布于 10个月前,共有 14 条评论 本文推荐 11 个非常棒的 React Native 开源组件,希望能给移动应用开发者提供帮助. React Native 是近期 Facebook 基于 MIT 协议开源的原生移动应用开发框架,已经用于 Facebook 的生产环境.React Native 可以使用最近非常流行的 React.js 库来开发 iOS 和 Android 原生 APP. 1. iOS 表单处理

推荐几款实用的Android Studio 插件

推荐几款实用的Android Studio 插件 泡在网上的日子 发表于 2015-10-09 10:47 第 17453 次阅读 插件,Android Studio 10 编辑推荐:稀土掘金,这是一个针对技术开发者的一个应用,你可以在掘金上获取最新最优质的技术干货,不仅仅是Android知识.前端.后端以至于产品和设计都有涉猎,想成为全栈工程师的朋友不要错过! 原文出处:http://www.jianshu.com/p/6f5f818afe4b 1.android-butterknife-ze

推荐10款最常用的Android开发工具

推荐10款最常用的Android开发工具 我们使用各种语言进行开发时,总是会用到各种各样的开发工具.有些开发工具是开发人员的必备品,有些则是为了提高开发效率而用.Android开发同样也会用到多种开发工具,供开发人员设计.创建.测试和发布程序时使用.下面向大家推荐十款常用的Android开发工具. 1.Eclipse w/ADT 虽然Eclipse并非唯一可用于开发Android应用的Java开发环境,但它是目前最欢迎的工具,有很大程度上是因为它的成本很低(免费),但最主要的原因还是它与其他An

推荐一款优秀的开源流媒体服务器系统:SRS(Simple RTMP Server)

最近视频流媒体直播的应用很火,各种手机端的直播.美女聊天室.财经直播等等.由于项目的需要,需要寻找一款合适的流媒体直播系统,如果从头开发,显然成本和周期都不能在可接受的范围内.幸运的是,我找到了SRS这款优秀的直播系统,该系统官方地址为:http://www.ossrs.net/srs.release/releases/ 首先不得不提的是:SRS是国人开发,国人开发的开源系统近几年越来越多,是非常令人惊喜的事情,并且有很多非常优秀的,非常令人开心. 另外不得不提的是:SRS的文档非常齐全,特别是

Android开源项目(二)

第二部分 工具库 主要包括那些不错的开发库,包括依赖注入框架.图片缓存.网络相关.数据库ORM建模.Android公共库.Android 高版本向低版本兼容.多媒体相关及其他. 一.依赖注入DI 通过依赖注入减少View.服务.资源简化初始化,事件绑定等重复繁琐工作 AndroidAnnotations(Code Diet)android快速开发框架项目地址:https://github.com/excilys/androidannotations文档介绍:https://github.com/