专栏首页程序员大飞Android RecyclerView浅析(分类型)

Android RecyclerView浅析(分类型)

Android RecyclerView浅析

1.RecyclerView概述&简介

简单介绍:

整体上看RecyclerView架构,提供了一种插拔式的体验,高度的解耦,异常的灵活,通过设置它提供的不同LayoutManager,ItemDecoration , ItemAnimator实现令人瞠目的效果。

你想要控制其显示的方式,请通过布局管理器LayoutManager

你想要控制Item间的间隔(可绘制),请通过ItemDecoration

你想要控制Item增删的动画,请通过ItemAnimator

你想要控制点击、长按事件,请自己写(擦,这点尼玛。)

给Recycler的Item的布局去设置margin,当然了这种方式不够优雅,我们文章开始说了,我们可以自由的去定制它,当然我们的分割线也是可以定制的。

ItemDecoration

我们可以通过该方法添加分割线:

mRecyclerView.addItemDecoration()

该方法的参数为RecyclerView.ItemDecoration,该类为抽象类,官方目前并没有提供默认的实现类(我觉得最好能提供几个)

提示:如果布局管理器里面设置的Horizontal就是行,如果是Vertical就是显示几列。

2.实现步骤:

布局,适配器,继承于RecyclerView的适配器,

viewHolder继承于RecyclerView的适配器

设置泛型,然后再次实现对应的方法

3.RecyclerView各个布局管理器的说明

1).线性布局管理器:

mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));  

参数一:上下文; 参数二:指明线性布局的方向,参数三:是否为倒序排列;

2).网格布局管理器:

mRecyclerView.setLayoutManager(new GridLayoutManager(this, 4, GridLayoutManager.VERTICAL, false));

参数一:上下文; 参数二:指明行数(Horizontal),或列数(Vertical);

参数三:指明方向;参数四:是否倒序;

3).瀑布流布局管理器

mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(4, StaggeredGridLayoutManager.VERTICAL));

参数一:指明行数(Horizontal),或列数(Vertical);

参数二:指明方向;

4.给RecyclerView的Item设置点击事件有两种:

方式一:在Adapter的onBindViewHolder()方法中设置,也可以定义一个接口回调,让MainAcitivity实现自定义的接口,然后在MainActivity设置接口回调的监听即可:mRvAdapter.setonItemClickListener();

5.一般的RecyclerView

5.1布局

	<android.support.v7.widget.RecyclerView

        android:id="@+id/recyclerView"

        android:layout_width="match_parent"

        android:layout_height="match_parent" />

5.2初始化控件,设置布局管理器(3种)

	recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
        // 设置线性布局管理器
        recyclerView.setLayoutManager(new LinearLayoutManager(this));

5.3设置适配器

    recyclerView.setAdapter(new MyAdapter());

5.4创建适配器

写一个类继承于Recyclerview的Adapter重写几个方法,写一个viewHolder,然后设置Adapter的泛型为当前的ViewHolder,如果有不一样的就要重写其方法

关于其几个方法的说明:

	class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

		// 创建一个ViewHolder,加载一个视图

        @Override

        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(AddHeadRecyclerViewActivity.this).inflate(R.layout.item, parent, false);
            return new ViewHolder(view);
        }

		// 绑定ViewHolder,一般进行数据的绑定操作
        @Override
        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

        }

		// 返回有多少条Item
        @Override
        public int getItemCount() {
            return 9;
        }

		// ViewHolder
        class ViewHolder extends RecyclerView.ViewHolder {
            public ViewHolder(View itemView) {
                super(itemView);
            }
        }
    }

5.5在onCreateViewHolde中,创建一个ViewHolder(),一般为加载一个布局文件,注意此处inflate和LayoutInflater的区别

6.分类型的RecyclerView

6.1重写方法和和一般的类似,多了一个getItemViewType()方法下面是分类的代码示例及解释

	public class HomeRecycleAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    public static final String GOODS_BEAN = "goods_bean";
    /**
     * 上下文
     */

    private Context mContext;
    /**
     * 数据Bean对象
     */
    private ResultBean resultBean;
    /**
     * 五种类型
     */
     
    /**
     * 横幅广告
     */
    public static final int BANNER = 0;

    /**
     * 频道
     */
    public static final int CHANNEL = 1;

    /**
     * 活动
     */
    public static final int ACT = 2;

    /**
     * 秒杀
     */
    public static final int SECKILL = 3;
    /**
     * 推荐
     */
    public static final int RECOMMEND = 4;

    /**
     * 热卖
     */
    public static final int HOT = 5;

    /**
     * 当前类型
     */
    public int currentType = BANNER;

    private final LayoutInflater mLayoutInflater;

    public HomeRecycleAdapter(Context mContext, ResultBean resultBean) {

        this.mContext = mContext;

        this.resultBean = resultBean;

        mLayoutInflater = LayoutInflater.from(mContext);

    }

    /**
     * 根据位置得到类型-系统调用
     * @param position
     * @return
     */
    @Override

    public int getItemViewType(int position) {

        switch (position) {
            case BANNER:
                currentType = BANNER;
                break;
            case CHANNEL:
                currentType = CHANNEL;
                break;
            case ACT:
                currentType = ACT;
                break;
            case SECKILL:
                currentType = SECKILL;
                break;
            case RECOMMEND:
                currentType = RECOMMEND;
                break;
            case HOT:
                currentType = HOT;
                break;
        }

        return currentType;

    }

    /**

     * 返回总条数,共六种类型

     * @return

     */

    @Override

    public int getItemCount() {

        return 6;

    }

    @Override

    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        if (viewType == BANNER) {

            return new BannerViewHolder(mLayoutInflater.inflate(R.layout.banner_viewpager, null), mContext, resultBean);

        } else if (viewType == CHANNEL) {

            return new ChannelViewHolder(mLayoutInflater.inflate(R.layout.channel_item, null), mContext);

        } else if (viewType == ACT) {

            return new ActViewHolder(mLayoutInflater.inflate(R.layout.act_item, null), mContext);

        } else if (viewType == SECKILL) {

            return new SeckillViewHolder(mLayoutInflater.inflate(R.layout.seckill_item, null), mContext);

        } else if (viewType == RECOMMEND) {

            return new RecommendViewHolder(mLayoutInflater.inflate(R.layout.recommend_item, null), mContext);

        } else if (viewType == HOT) {

            return new HotViewHolder(mLayoutInflater.inflate(R.layout.hot_item, null), mContext);

        }

        return null;

    }

    /**

     * 绑定数据

     * @param holder

     * @param position

     */

    @Override

    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

        if (getItemViewType(position) == BANNER) {

            BannerViewHolder bannerViewHolder = (BannerViewHolder) holder;

            bannerViewHolder.setData(resultBean.getBanner_info());

        } else if (getItemViewType(position) == CHANNEL) {

            ChannelViewHolder channelViewHolder = (ChannelViewHolder) holder;

            channelViewHolder.setData(resultBean.getChannel_info());

        } else if (getItemViewType(position) == ACT) {

            ActViewHolder actViewHolder = (ActViewHolder) holder;

            actViewHolder.setData(resultBean.getAct_info());

        } else if (getItemViewType(position) == SECKILL) {

            SeckillViewHolder seckillViewHolder = (SeckillViewHolder) holder;

            seckillViewHolder.setData(resultBean.getSeckill_info());

        } else if (getItemViewType(position) == RECOMMEND) {

            RecommendViewHolder recommendViewHolder = (RecommendViewHolder) holder;

            recommendViewHolder.setData(resultBean.getRecommend_info());

        } else if (getItemViewType(position) == HOT) {

            HotViewHolder hotViewHolder = (HotViewHolder) holder;

            hotViewHolder.setData(resultBean.getHot_info());

        }

    }

    class HotViewHolder extends RecyclerView.ViewHolder {

        private TextView tv_more_hot;

        private GridView gv_hot;

        private Context mContext;



        public HotViewHolder(View itemView, Context mContext) {

            super(itemView);

            tv_more_hot = (TextView) itemView.findViewById(R.id.tv_more_hot);

            gv_hot = (GridView) itemView.findViewById(R.id.gv_hot);

            this.mContext = mContext;

        }



        public void setData(final List<ResultBean.HotInfoBean> data) {

            HotGridViewAdapter adapter = new HotGridViewAdapter(mContext, data);

            gv_hot.setAdapter(adapter);



            //点击事件

            gv_hot.setOnItemClickListener(new AdapterView.OnItemClickListener() {

                @Override

                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

                    // Toast.makeText(mContext, "position:" + position, Toast.LENGTH_SHORT).show();

                    String cover_price = data.get(position).getCover_price();

                    String name = data.get(position).getName();

                    String figure = data.get(position).getFigure();

                    String product_id = data.get(position).getProduct_id();

                    GoodsBean goodsBean = new GoodsBean(name, cover_price, figure, product_id);



                    Intent intent = new Intent(mContext, GoodsInfoActivity.class);

                    intent.putExtra(GOODS_BEAN, goodsBean);

                    mContext.startActivity(intent);

                }

            });

        }

    }

6.2一般将分类型的每种类型都声明为一个常量,然后根据常量来创建对应的ViewHolder(加载自己对应的布局文件),然后在根据类型绑定自己的对应的数据;所以每一中类型都要对应自己的ViewHolder,进而实现分类型;一般还有实现其有参构造为了传递和初始化相关数据;

7.RecyclerView三种布局管理添加头的方式:

7.1LinearLayoutManager添加头部

直接分类型就可以 第一个头部是第一种类型

7.2GridLayoutManager添加头部

代码

RecyclerView rv = (RecyclerView) findViewById(R.id.rv);



 GridLayoutManager manager = new GridLayoutManager(this,2);



 // 重点在这 需要实现这个方法

 manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {

 @Override

 public int getSpanSize(int position) {

       return position == 0 ? 2 : 1;

 });



 rv.setLayoutManager(manager);



 rv.setAdapter(new MyAdapter());



//解释:明明头部返回的是2 怎么会是这个效果呢?返回2不应该是2列返回1是1列吗?

position 就是我们的item位置



getSpanSize返回的值就是我们的跨列度

  

GridLayoutManager manager = new GridLayoutManager(this,2); 

 

大家看这个方法里的第二个参数,我们是不是指定了2列 



而我们的头是不是返回了2然后显示了一行,没错,就是所占的列数。也就是我们的头占了2列 第二个item往后只占一列也就是一个item占屏幕的一半。

###7.3StaggeredGridLayoutManager添加头部

在adapter中重写些方法

	@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;



			//设置全屏

            p.setFullSpan(holder.getLayoutPosition() == 0);

    	}

	}

onViewAttachedToWindow()

当列表项出现到可视界面的时候调用

8.inflate&LayoutInflater

其实View.inflate的底层就是 LayoutInflate.form()
View.inflate
public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) {

        LayoutInflater factory = LayoutInflater.from(context);

        return factory.inflate(resource, root);

}

inflate(int resource, ViewGroup root, boolean attachToRoot)

1. 如果root为null,attachToRoot将失去作用,设置任何值都没有意义。
2. 如果root不为null,attachToRoot设为true,则会给加载的布局文件的指定一个父布局,即root。
3. 如果root不为null,attachToRoot设为false,则会将布局文件最外层的所有layout属性进行设置,当该view被添加到父view当中时,这些layout属性会自动生效。
4. 在不设置attachToRoot参数的情况下,如果root不为null,attachToRoot参数默认为true。

今天给大家简单的介绍了一下RecyclerView的一般用法和分类的用法,一般我们开发使用最多的也就是这两种了,希望对大家能有所帮助。

Thanks all.

本文首发于我的微信公众号,更多干货文章,请扫描二维码订阅哦:

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Android registerActivityLifecycleCallbacks 使用

    使用这个类,我们可以很方便的监听到 Activity 的状态,从而可以判断 APP 是否在前台或者后台等。

    IT大飞说
  • Android 自定义一个简单的刮奖 View

    使用相对布局,先写一个 TextView,然后自定义一个 EraseView,写一个同样大小的 EraseView 覆盖在 TextView 上面即可。

    IT大飞说
  • Android点击两次返回键退出应用

    IT大飞说
  • Android RecyclerView的简便写法

    RecyclerView现在可以说是很常用了吧?RecyclerView自然是很方便的控件,但用多了有时候对一些重复性代码也是感觉挺麻烦的,于是乎我就将一些重复...

    叶应是叶
  • 恕我直言,我怀疑你并不会生成随机数

    有一次,我在逛 Stack Overflow 的时候,发现有这样一个问题:“Java 中如何产生一个指定范围内的随机数”,我心想,“就这破问题,竟然有 398 ...

    沉默王二
  • Flutter完整开发实战详解(二、 快速开发实战篇)

     作为系列文章的第二篇,继《Flutter完整开发实战详解(一、Dart语言和Flutter基础)》之后,本篇将为你着重展示:如何搭建一个通用的Flutter ...

    恋猫
  • dotnet bitmap

    sofu456
  • Java高并发之无锁与Atomic源码分析

    用户1216491
  • Flutter完整开发实战详解(二、 快速开发实战篇)

     作为系列文章的第二篇,继《Flutter完整开发实战详解(一、Dart语言和Flutter基础)》之后,本篇将为你着重展示:如何搭建一个通用的Flutter ...

    恋猫
  • 一个根据双色球历史数据预测未来中奖号码的Java程序

    Jerry Wang

扫码关注云+社区

领取腾讯云代金券