android常用控件RecyclerView(三) RecyclerView的使用

来源:互联网 发布:淘宝店中国制造 编辑:程序博客网 时间:2024/05/02 01:18

  当我们需要对大量的数据进行展示的时候,通常会用到ListView、GridView等。而Recycler则可以看做是能够完成ListView、GridView、StaggeredGridView的一个强大容器。
  先来看看RecyclerView的基本使用。
  通常在使用ListView等控件的时候都需要一个数据适配器,在RecyclerView中也继承了这个优良的传统。
为了使RecyclerView将数据的样式展示成不同的样式,它为我们提供了LayoutManager用来控制数据展示的布局。通过设置ItemDecoration可以控制分分割线的样式,通过ItemAnimator可以控制增删数据时的动画效果。

一 Recycler基础使用

下面,先来一个ListView布局的列子。

public class MainActivity extends Activity {    RecyclerView recyclerView;    ArrayList<Product> productList;    private StaggeredGridLayoutManager manager;    MyNormalRecyclerAdapter adapter;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        recyclerView= (RecyclerView) findViewById(R.id.recycler);        //layoutManager        recyclerView.setLayoutManager(new LinearLayoutManager(this));        initData();        //adapter        adapter=new MyNormalRecyclerAdapter(productList);        recyclerView.setAdapter(adapter);        }        private void initData() {        productList = new ArrayList<Product>();        Product product;        for (int i = 0; i < 30; i++) {            int asd = R.drawable.ic_launcher;            product = new Product(asd, "" + i);            productList.add(product);        }    }}

在上面代码中,先初始化了一个数据源,之后通过 recyclerView.setLayoutManager(new LinearLayoutManager(this));将recyclerview的设置成ListView的显示样式。
  这里使用了一个自定义的adapter。

public class MyRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>/*<RecyclerView.ViewHolder>*//*RecyclerView.Adapter*/{    public static final int TYPE_HEADER = 0;    public static final int TYPE_NORMAL = 1;    public static final int TYPE_FOOTER = 2;    private View mHeaderView;    private View mFooterView;    ArrayList<Product> products;    public int getItemViewType(int position) {        Log.d("HK", "getItemViewType  called "+position);        if(mHeaderView == null) return TYPE_NORMAL;        if(position == 0) return TYPE_HEADER;        return TYPE_NORMAL;    }    public MyRecyclerAdapter(ArrayList<Product> list) {        products = list;    }    @Override    public int getItemCount() {        return 0;    }    public int getRealPosition(RecyclerView.ViewHolder holder) {        int position = holder.getLayoutPosition();        Log.d("HK", "getRealPosition  called "+position);        return mHeaderView == null ? position : position - 1;    }    @Override    public void onBindViewHolder(ViewHolder arg0, final int position) {        Log.d("HK", "onBindViewHolder  called "+position);        if(getItemViewType(position) == TYPE_HEADER) return;        final int pos = getRealPosition(arg0);        final Product data = products.get(pos);        if(arg0 instanceof  MasonryView) {            ((MasonryView) arg0).textView.setText(products.get(position).getTitle());            ((MasonryView) arg0).imageView.setImageResource(products.get(position).getImg());        }        ImageView image = ((MasonryView)arg0).imageView;        TextView text = ((MasonryView)arg0).textView;        image.setImageResource(products.get(position).getImg());        text.setText(products.get(position).getTitle());        View view = ((MasonryView)arg0).view;            }    @Override    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        Log.d("HK", "onCreateViewHolder  called "+viewType);        if(mHeaderView != null && viewType == TYPE_HEADER) return new MasonryView(mHeaderView);        View layout = LayoutInflater.from(parent.getContext()).inflate(R.layout.receycler_item, parent, false);        return new MasonryView(layout);    }     class MasonryView extends  RecyclerView.ViewHolder{        ImageView imageView;        TextView textView;        View view;       public MasonryView(View itemView){           super(itemView);           view = itemView;           imageView= (ImageView) itemView.findViewById(R.id.item_img );           textView= (TextView) itemView.findViewById(R.id.item_title);       }    }}

在这个适配其中,通过onBindViewHolder来进行数据的绑定,而通过onCreateViewHolder来返回视图。代码中出现的mHeaderView等将在后文进行介绍。
有了这个适配器后,通过上一段的代码,就可以呈现出ListView的显示效果了。当然,如果需要将显示效果更改为gridview,只需要将
recyclerView.setLayoutManager(new LinearLayoutManager(this));更改为 mRecyclerView.setLayoutManager(new GridLayoutManager(this,4))就行。
  当然如果要加上分割线,只需要添加

 SpacesItemDecoration spaces = new SpacesItemDecoration(16);        recyclerView.addItemDecoration(spaces);

SpacesItemDecoration 是自定义的一个类,可以设置分割线的样式等。

public class SpacesItemDecoration extends RecyclerView.ItemDecoration {    private int space;    public SpacesItemDecoration(int space) {        this.space=space;    }    @Override    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {        outRect.left=space;        outRect.right=space;        outRect.bottom=space;//        outRect.top=space;        if(parent.getChildAdapterPosition(view)==0){//            outRect.top=space;        }    }

如果需要对recyclerview中添加点击事件,则需要自己在适配器中添加接口,添加方式也比较简单。代码如下:
现在适配器中设置一个回调。

private OnItemClickLitener mOnItemClickLitener;    public interface OnItemClickLitener    {        void onItemClick(View view, int position);        void onItemLongClick(View view , int position);    }     public void onBindViewHolder(final ViewHolder viewholder, final int position) {                 ......            if (mOnItemClickLitener != null)            {                viewholder.itemView.setOnClickListener(new OnClickListener()                {                    @Override                    public void onClick(View v)                    {                        int pos = viewholder.getLayoutPosition();                        mOnItemClickLitener.onItemClick(viewholder.itemView, pos);                    }                });                viewholder.itemView.setOnLongClickListener(new OnLongClickListener()                {                    @Override                    public boolean onLongClick(View v)                    {                        int pos = viewholder.getLayoutPosition();                        mOnItemClickLitener.onItemLongClick(viewholder.itemView, pos);                        return false;                    }                });            }        }    }

接下来在需要点击的地方实现回调

adapter.setOnItemClickLitener(new OnItemClickLitener() {            @Override            public void onItemClick(View view, int position) {                // TODO Auto-generated method stub                Toast.makeText(MainActivity.this, position + " click",                        Toast.LENGTH_SHORT).show();            }            @Override            public void onItemLongClick(View view, int position) {                // TODO Auto-generated method stub                Toast.makeText(MainActivity.this, position + " long click",                        Toast.LENGTH_SHORT).show();                        //mAdapter.removeData(position);            }        });

(二)为Recycler添加头部和底部

  RecyclerView支持在容器中添加头部和底部来打造优美的视觉效果。由于头部和底部都是作为recyvlerview容易的一个view。为了将其与普通的ItemView进行区分,则需要使用到public int getItemViewType(int position)。先来看看在适配器中代码。

 private View mHeaderView;    private View mFooterView;    public static final int TYPE_HEADER = 0;    public static final int TYPE_NORMAL = 1;    public static final int TYPE_FOOTER = 2; public void setHeaderView(View headerView) {        mHeaderView = headerView;        notifyItemInserted(0);        Log.d("HK", "setHeaderView  called" );    } public void setFooterView(View footerView) {        mFooterView = footerView;        int footIndex = getItemCount()-1;        notifyItemInserted(footIndex);        Log.d("HK", "setFooterView  called and index = "+footIndex);    } public void onBindViewHolder(final ViewHolder viewholder, final int position) {        // TODO Auto-generated method stub        if(getItemViewType(position) == TYPE_HEADER) return;        if(getItemViewType(position) == TYPE_FOOTER) return;        final int pos = getRealPosition(viewholder);        Log.d("HK", "onBindViewHolder  called position pos "+position+" "+pos);    }    public int getItemViewType(int position) {        Log.d("HK", "getItemViewType  called "+position);        if((mHeaderView == null) && (mFooterView == null)) return TYPE_NORMAL;        if(position == 0) return TYPE_HEADER;        if(position == getItemCount()-1) return TYPE_FOOTER;        return TYPE_NORMAL;    }

上面的代码中在适配器中添加了增加头部的函数,增加底部的函数以及对VIEW类型的返回。因为加入了头部和底部,那么普通item的位置就和为添加之前有了一定的差别,因此为了获取位置,我们使用了getRealPosition(viewholder);

    public int getRealPosition(RecyclerView.ViewHolder holder) {        int position = holder.getLayoutPosition();        Log.d("HK", "getRealPosition called "+position);        return mHeaderView == null ? position : position - 1;    }

将适配器做完改造后,只需要在使用中进行调用就行。

  setHeader(recyclerView);  setFooter(recyclerView);  private void setFooter(RecyclerView view) {        View footerView = LayoutInflater.from(this).inflate(R.layout.footerlayout, view, false);        adapter.setFooterView(footerView);    }      private void setHeader(RecyclerView view) {        View header = LayoutInflater.from(this).inflate(R.layout.titlelayout, view, false);        adapter.setHeaderView(header);    }   

但是,按照上述做法我们会发现并不能实现想要的效果。这是应为作为gridview 头部索引为0,如果gridview 分为了多列,那么这个0只会在第一个位置,而不会占用一整行。为了解决这个问题,需要在适配器中添加如下代码。

 @Override    public void onAttachedToRecyclerView(RecyclerView recyclerView) {        super.onAttachedToRecyclerView(recyclerView);        RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();        if(manager instanceof GridLayoutManager) {            final GridLayoutManager gridManager = ((GridLayoutManager) manager);            gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {                @Override                public int getSpanSize(int position) {                    return (getItemViewType(position) == TYPE_HEADER||getItemViewType(position) == TYPE_FOOTER)                            ? gridManager.getSpanCount() : 1;                }            });        }    }

当然 ,如果我们将样式设置为瀑布流类型就需要添加如下代码:

@Override    public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {        super.onViewAttachedToWindow(holder);        ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();        if(lp != null && lp instanceof StaggeredGridLayoutManager.LayoutParams) {            StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;            if(holder.getLayoutPosition() == 0 ||(holder.getLayoutPosition() == getItemCount()-1)) {                p.setFullSpan(true);            }        }    }

以上代码可在GITHUB下载。
GIT:https://github.com/everyhappy/RecyclerViewDemo

0 0