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

13 篇文章 0 订阅
1 篇文章 0 订阅

  当我们需要对大量的数据进行展示的时候,通常会用到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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值