recyclerViewAndroid开发@IT·互联网

RecyclerView-Adapter系列简述(第1篇)

2016-08-16  本文已影响1068人  子木小先生

从这篇文章文章开始将会连载几篇文章简单描述下最近抽空针对RecyclerViewAdapter做的一个扩展库。系列文章是对扩展库逐步进行扩展的,有一定的先后关系,所以阅读的话还是按照这个顺序比较好。

这篇先不开始描述怎么去扩展,先说一下这个扩展库将拥有什么样的功能以及如何使用,也就是告诉读者这些功能是不是符合口味,能不能吸引再往下读。
该库github地址:
https://github.com/yangxiaoweihn/RecyclerViewAdapter

该系列内容已经完结,其他部分可以点击下列阅读:
RecyclerView-为Adapter添加头部、尾部及事件响应(第2篇)
RecyclerView-数据域的操作方法(第3篇)
RecyclerView-为Adapter增加滑动菜单支持(第4篇)
RecyclerView-为Adapter增加粘性头部支持(第5篇)

本篇主要描述以下几方面内容:

  1. 扩展库如何在项目中使用
  2. 扩展库具有的功能
  3. 贴图看看效果
  4. 扩展库的api使用说明

扩展库的使用

该库已经打包上传到了mavenjcenter仓库,使用Android Studio开发的同学肯定都知道怎么从仓库引入库的。
特殊注意:另外,这系列文章是针对源码版本2.0描述的

    compile 'ws.dyt.view:recyclerview-adapter-hf:2.0'

具有的功能

  1. 可以添加、删除任意数量的头部、尾部(就像ListView那样)
  2. 可以添加系统头部、尾部(数量和使用上做了限制,在使用上尽量不要去使用这部分),具体说明将会在之后的文章中进行阐述。
  3. 可以针对不同的item添加滑动菜单(目前只支持左滑、右滑),并且菜单定制性高
  4. 支持粘性视图,同时支持滑动菜单

效果图

在能让读者有足够的好奇心读以下的文章前,先贴几张效果图,拿效果图最能说明该库拥有的功能。

1.png 2.png 3.png 4.png 5.png 6.png 7.png

好了,效果图已经贴完,如果觉得这些功能不够吸引的话,同学就可以止步了,因为只有得系列文章主要是为了阐述以上功能的开发过程及思路。

api使用说明

首先要说明一点:该api的使用与系统原生提供的有区别,不要思维定式。简单说起来就是使用更简单,大概姿势如下:
1. 构造(构造方法)
2. 数据绑定
3. 多类型支持(设置布局,如果需要的话)
4. 事件
5. 添加头部尾部控件
6. 横跨列处理
7. 添加菜单
8. 添加粘性头部

该库主要实现了两个具有一定功能的Adapter,命名为SuperAdapterSuperPinnedAdapter。从实现上来讲,SuperPinnedAdapter间接继承自SuperAdapter,所以功能上就不言而喻了。
SuperAdapter具有添加头部尾部、以及滑动菜单功能,而SuperPinnedAdapter在此基础上增加了粘性视图的支持。

通过构造方法进行初始化(具体的参数说明请看注释)

/** 
    * 调用该构造方法时需要调用 {@link #getItemViewLayout(int)} 设置item布局 
    * @param context 
    * @param datas 
    */
  public SuperAdapter(Context context, List<T> datas) {
      super(context, datas);
  }
  /** 
    * 调用该构造方法时默认数据项都采用 itemLayoutResId 布局,同样可以调用 {@link #getItemViewLayout(int)} 重新设置item布局 
    * @param context 
    * @param datas 
    * @param itemLayoutResId 
    */
public SuperAdapter(Context context, List<T> datas, @LayoutRes int itemLayoutResId) {    
      this(context, datas);
}

以上两个构造方法最大的区别是:用第一种方法构造后需要调用getItemViewLayout()设置item的布局。用后一种的话已经设置了item布局,不过这种方式是所有的item布局都是一样的。

数据绑定

数据的绑定在原生里是onBindViewHolder(),而在这里,将该方法进行了屏蔽,而是用convert()方法(使用上与onBindViewHolder()一致,但是也更简单),可以简单的将他俩看成是对等的关系,但是事实上不是这样的,具体的我将会在后续的文章中进行具体描述。

  /** 
    * 绑定数据 
    * @param holder 
    * @param position  数据域从0开始,已经除去头部       
    */
  abstract
  public void convert(BaseViewHolder holder, int position);

该方法的第一个参数该库做了进一步封装,具体来说就是整个库里BaseViewHolder类无法被扩展,所有常用的操作方法已经在该类中进行了封装(后续版本在决定是否可以允许该类扩展),BaseViewHolder的功能将会在后面的文章进行描述。BaseViewHolder的链条操作:

  //只是一个例子而已,旨在说明链条操作,不必注意实体类是什么
  CourseResult.Course e = getItem(position).data;
  holder.
      setText(R.id.tv_name, e.name).
      setText(R.id.tv_length, e.length);

多item支持

通过构造方法已经知道,用构造方法是没有办法设置Adapter的多item样式支持的。那么在该库中,通过以下方法进行设置:

  /**  
    * 提供item对应的布局 
    */
public int getItemViewLayout(int position) {}

事件

网上一大片文章都在讲RecyclerView怎么设置item的点击事件云云,事实上确实很简单,RecyclerView暴露的方法就那么几个,所以在这里事件是怎么加上去的也将在后续的文章中阐述,这里只需要知道该库一定也提供了设置事件监听的方法。
对item的点击事件支持以下两种:

  /** 
    * 点击事件 
    */
  public interface OnItemClickListener {    
      void onItemClick(View itemView, int position);
  }
  /** 
    * 长按事件 
    */
  public interface OnItemLongClickListener {    
      void onItemLongClick(View itemView, int position);
  }

设置监听器:

  //设置点击事件
  adapter.setOnItemClickListener(new SuperAdapter.OnItemClickListener() {    
      @Override    
      public void onItemClick(View itemView, int position) {     
      }
});
  //设置长按事件
  adapter.setOnItemLongClickListener(new SuperAdapter.OnItemLongClickListener() {    
      @Override    
      public void onItemLongClick(View itemView, int position) {     
      }
});

添加头部、尾部控件

原生RecyclerView并没有提供像ListView中那样可以随意添加header和footer的api,但是在实际的场景中我们确实需要这样的功能,那么该库也一定提供了这样的方法。
首先需要简单说一下SuperAdapter数据域的构成:

  {
      item_sys_header - item_header - 
      item_data - 
      item_footer - item_sys_footer
  }
从上面的结构中可以看到,大体分为3中(header部分、数据部分、footer部分),细分的话,头部又分为系统header部分(item_sys_header)和用户header部分(item_header),footer部分分为系统footer部分(item_footer)和用户footer部分(item_sys_footer)。
我为什么要这么划分呢,在实现上是有一些考虑的,头部和尾部不要去污染数据部分(分离),这样在扩展上更好一些。一般在使用时系统header和系统footer可以忽略,加这两个的用途也是为了扩展用,比如在我的另外一个上拉加载库中就用了系统footer。

主要提供了一下几个api:

final
public void addHeaderView(View view);
final
public void addHeaderView(View view, boolean changeAllVisibleItems);
final
public void removeHeaderView(View view);
final
public void removeHeaderView(View view, boolean changeAllVisibleItems);
final
public void addFooterView(View view);
final
public void addFooterView(View view, boolean changeAllVisibleItems);
final
public void removeFooterView(View view);
final
public void removeFooterView(View view, boolean changeAllVisibleItems);

其中changeAllVisibleItems表示是否只刷新可见区域(为true时),否则只刷新当前发生变化的item,默认为false

横跨列的api

RecyclerView的布局管理器是GridLayoutManager或者StaggeredGridLayoutManager时,有些item需要横跨所有列,这种情况下我们也提供了以下api去设置,默认为false,表示保持管理器设置,为true时表示横跨。

/**
 * 设置是否横跨
 * @param position
 * @return
 */
protected boolean isFullSpanWithItemView(int position) {
    return false;
}

添加菜单及菜单事件

public List<MenuItem> onCreateMultiMenuItem(int viewType) {
    List<MenuItem> mm = new ArrayList<>();
    mm.add(new MenuItem(R.layout.menu_item_test_delete, MenuItem.EdgeTrack.RIGHT, 01));
    mm.add(new MenuItem(R.layout.menu_item_test_mark, MenuItem.EdgeTrack.RIGHT, 02));
    return mm;
}
@Override
public boolean isCloseOtherItemsWhenThisWillOpen() {
    return true;}adapter.setOnItemMenuClickListener(new OnItemMenuClickListener() {
    @Override
    public void onMenuClick(SwipeLayout swipeItemView, View itemView, View menuView, int position, int menuId) {
        if (menuId == 01) {
            swipeItemView.closeMenuItem();
            Log.d("DEBUG", "--menu: 删除 -> position: " + position + " , menuId: " + menuId);
            Toast.makeText(getContext(), "删除", Toast.LENGTH_SHORT).show();
        } else if (menuId == 02) {
            Log.d("DEBUG", "--menu: 关注 -> position: " + position + " , menuId: " + menuId);
            Toast.makeText(getContext(), "加关注", Toast.LENGTH_SHORT).show();
        }
    }
});

添加粘性头部及数据绑定

注意粘性头部的AdapterPinnedAdapter.

@Override
public int getPinnedItemViewLayout() {
    return R.layout.item_pinned;
}
@Override
public void convertPinnedHolder(BaseViewHolder holder, int position, int type) {
    holder.setText(R.id.tv_text_pinned, getItem(position).data.title);
}

概括的介绍就到这里。

上一篇下一篇

猜你喜欢

热点阅读