recycleview

why recycleview ?  是ListView的更高度定制版,当你需要高效的展示大量数据时候,动态改变列表样式的时候,就用这个。

当然,如果只是动态展示数据,listview也可以做到,用它替代listview的原因有几个:

  1. 简介中提到的它封装了viewholder的回收复用。
  2. RecyclerView使用布局管理器管理子view的位置(目前尚只提供了LinearLayoutManager),你能够使用复杂的布局来展示一个列表 ,再不用拘泥于ListView的线性展示方式,如果之后提供其他custom LayoutManager的支持。
    StaggeredGridLayoutManager mStaggeredGridLayoutManager =
    new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
    //表示两列,并且是竖直方向的瀑布流
    mRecyclerView.setLayoutManager(mStaggeredGridLayoutManager);
    在布局上支持三种StaggeredGridLayoutManager(错列的), GridLayoutManager LinearLayoutManager
  3. 自带了ItemAnimation,可以设置加载和移除时的动画,方便做出各种动态浏览的效果。
  4. 分开的view 
    我们平时用listview的时候,adapter一般这么写的

    if (convertView == null) {
          holder = new ViewHolder();
           LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
           convertView = inflater.inflate(
                   R.layout.list_device_binding, parent, false);
    
           holder.deviceImage = (ImageView) convertView
                   .findViewById(R.id.bluetoothDeviceImage);
           holder.deviceName = (TextView) convertView
                   .findViewById(R.id.bluetoothDeviceName);
           holder.deviceType = (TextView) convertView
                   .findViewById(R.id.bluetoothDeviceType);
           convertView.setTag(holder);
       } else {
           holder = (ViewHolder) convertView.getTag();
       }
    

    但是,到了这里,他把他分隔开了,如下

    @Override
    public A onCreateViewHolder(ViewGroup parent, int viewType) {       
        final View view = LayoutInflater.from(mContext).
              inflate(R.layout.listitem_track_history, parent, false);
        return new ViewHolder(view); 
     }  
    
    @Override
    public void onBindViewHolder(A holder, int position) {
         Data da=getData(position);
        holder.tvDate.setText(da.getDate());
    }
    

    我们就再也不用像以前那样写了.

  5. 相对简单 
    我们看下Listview他背后的继承关系

    public class ListView extends AbsListView 
    public abstract class AbsListView extends AdapterView<ListAdapter>
    public abstract class AdapterView<T extends Adapter> extends ViewGroup 
    

    三重继承,内容还挺多的,不是直接继承ViewGroup,而相反的RecycleView却是直接继承自ViewGroup的。

缺点:

目前相对于我们对listview经常用到的方法,有下面两个问题: 
1. 不能简单的加头和尾 header、footer
2. 不能简单的设置子item的点击事件。

具体的解决方案如下

  1. 不能简单的添加Head和Footer 
    在使用过程中,你发现你要添加头和尾不是很容易,因为没有直接的addHead和addFoot的方法了,不过这里有一个tumblr开源的库,可以让你实现这个功能,核心的代码如下

     @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
        if (isHeader(viewType)) {
            int whichHeader = Math.abs(viewType - HEADER_VIEW_TYPE);
            View headerView = mHeaders.get(whichHeader);
            return new RecyclerView.ViewHolder(headerView) { };
        } else if (isFooter(viewType)) {
            int whichFooter = Math.abs(viewType - FOOTER_VIEW_TYPE);
            View footerView = mFooters.get(whichFooter);
            return new RecyclerView.ViewHolder(footerView) { };
    
        } else {
            return mBase.onCreateViewHolder(viewGroup, viewType);
        }
    }
    
    
    
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
            if (position < mHeaders.size()) {
                // Headers don't need anything special  
        } else if (position < mHeaders.size() + mBase.getItemCount()) {
            // This is a real position, not a header or footer. Bind it.
            mBase.onBindViewHolder(viewHolder, position - mHeaders.size()); 
        } else {
            // Footers don't need anything special
        }
    }
    
    
    
    @Override   
    public int getItemViewType(int position) {
        if (position < mHeaders.size()) {
            return HEADER_VIEW_TYPE + position;
    
    } else if (position < (mHeaders.size() + mBase.getItemCount())) {
        return mBase.getItemViewType(position - mHeaders.size());
    
    } else {
        return FOOTER_VIEW_TYPE + position - mHeaders.size() - mBase.getItemCount();
    }
    
  2. 不能简单的添加点击事件onListItemClickListener 
    我们在使用listview设置子item的点击事件的时候,只需要像下面这么写

    listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
           @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    
               User user= parent.getItemAtPosition(position);                   
            }
    });
    

    但是,如果你使用这个RecycleView,会发现没有这个接口了。RecyclerView不再负责Item视图的布局及显示,所以RecyclerView也没有为Item开放OnItemClick等点击事件,这就需要我们自己实现,实现的方法像看到有三种,目前下面这种比较合理,所以推荐如下写法

    1. 让你的viewholder实现onClickListener,然后在这个方法里面回调我们自己写的接口。

      public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
      
          private TextView tvDate;             
      
          public ViewHolder(View itemView) {
              super(itemView);        
              tvDate = (TextView) itemView.findViewById(R.id.tv_date);
              itemView.setOnClickListener(this);
          }
      
          @Override
          public void onClick(View v) {
              if(listener!=null){
                  listener.onItemClick(getPosition(),mList.get(getPosition()));
              }
          }
      }
      
      //我们回调的自定义接口
      public  interface  onListItemClickListener{     
          void onItemClick(int position,TrackHistory mTrackHistory);
      }
      
    2. 接着在你的Adapter里面加多个set方法,里面设置回调接口

      public  void setOnItemClickListener(onListItemClickListener listener){      
          this.listener = listener;
      }
      

小结

从上面的简单比较,对于我而言如果不是最求很高的效率,我不选择用这个,确实有点不方便了

posted @ 2016-04-18 20:36  伟大的臭猪猪  阅读(619)  评论(0编辑  收藏  举报