当前位置:   article > 正文

RecycleView实现多布局

RecycleView实现多布局

自从RecycleView推出后,其功能的强大让你纯粹能忘掉ListView和GridView等列表布局,因为RecycleView能够代替他们,而且使代码更加健壮,今天要说的是目前APP中最流行的布局,如下图:

京东首页的多种布局格式

图中显示的就是一个RecycleView中实现排列的布局,下面我在一个RecycleView中运用了两种布局:

具有两种布局样式的RecycleView

下面我们看一下具体的代码实现,我先创建了两种类型的数据,OneTypeBean和TwoTypeBean,其中这两个类的成员变量不一致,将来是分别显示在两种不同的不居中的:

这是代码的目录结构

//第一种类型的bean
public  class OneTypeBean {
    private String name;
    private int imageView;
    private String professional;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getImageView() {
        return imageView;
    }

    public void setImageView(int imageView) {
        this.imageView = imageView;
    }

    public String getProfessional() {
        return professional;
    }

    public void setProfessional(String professional) {
        this.professional = professional;
    }

    public OneTypeBean(String name, int imageView, String professional) {
        this.name = name;
        this.imageView = imageView;
        this.professional = professional;
    }
}

//第二种类型的bean
public class TwoTypeBean {

    private String title;
    private int img;

    public TwoTypeBean(String title, int img) {
        this.title = title;
        this.img = img;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public int getImg() {
        return img;
    }

    public void setImg(int img) {
        this.img = img;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65

然后模拟创建两种类型的假数据:

oneList = new ArrayList<>();
        twoeList = new ArrayList<>();
        for (int i = 0; i < 4; i++) {
            oneList.add(new OneTypeBean("中华美食", images_1[i % 6], "独特的西北特色"));
        }
        for (int i = 0; i < 4; i++) {
            twoeList.add(new TwoTypeBean("[ 女人装 ]", images_2[i % 9]));
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

将这两种假数据传递到RecycleView的Adapter中,因为想将两种类型的数据排放在两种不同的布局之中,所以我在Adapter定义了两个整型常量:


    public static final int ONE_TYPE = 1;
    public static final int TWO_TYPE = 2;
  • 1
  • 2
  • 3

然后创建了两种数据结构分别存放每个position的类型和每个位置相对应的type:

private List<OneTypeBean> oneList;
    private List<TwoTypeBean> twoList;
    private List<Integer> types = new ArrayList<>();
    private Map<Integer, Integer> mPosition = new HashMap<>();

    public MyAdapter(Context mContext, List<OneTypeBean> oneList, List<TwoTypeBean> twoList) {
        this.mContext = mContext;
        this.oneList = oneList;
        this.twoList = twoList;

        for (int i = 0; i < oneList.size(); i++) {
            types.add(ONE_TYPE);
            mPosition.put(i,ONE_TYPE);

        }
        for (int i = 0; i < twoList.size(); i++) {
            types.add(TWO_TYPE);
            mPosition.put(i+oneList.size(),TWO_TYPE);

        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

然后重写Adapter中的一个方法,返回该数据的类型常量:

 @Override
    public int getItemViewType(int position) {

        return mPosition.get(position);
    }
  • 1
  • 2
  • 3
  • 4
  • 5

对于RecycleView的高效体现在它创建的ViewHolder来缓冲布局,不必为此创建,达到布局复用,减少内存的消耗和界面的卡顿,我在这里先创建了一个抽象的泛型为* *的AbstractTypeViewHolder继承RecycleView的ViewHolder;

public abstract class AbstractTypeViewHolder<T> extends RecyclerView.ViewHolder{

    public AbstractTypeViewHolder(View itemView) {
        super(itemView);
    }


}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

然后单独OneTypeViewHolder和TwoTypeViewHolder分别继承AbstractTypeViewHolder,然后写一个构造函数,绑定布局:

//第一种类型的ViewHolder
public class OneTypeViewHolder extends AbstractTypeViewHolder<OneTypeBean> {
    public ImageView header;
    public TextView name;
    public TextView describe;
    public OneTypeViewHolder(View itemView) {
        super(itemView);
        header = (ImageView) itemView.findViewById(R.id.iv_header);
        name = (TextView)itemView.findViewById(R.id.tv_name);
        describe = (TextView)itemView.findViewById(R.id.tv_describe);
    }


}
//第二中类型的ViewHolder

public class TwoTypeViewHolder extends AbstractTypeViewHolder<TwoTypeBean> {
    public ImageView iv_girl;
    public TextView tv_describe;
    public TwoTypeViewHolder(View itemView) {
        super(itemView);
        iv_girl = (ImageView) itemView.findViewById(R.id.iv_food);
        tv_describe = (TextView)itemView.findViewById(R.id.tv_title);
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

将这两种ViewHolder写好后,就是将这两种进行布局复用的ViewHolder添加到我们的Adapter中,在Adapter中根据Type来创建不同的ViewHolder:

 LayoutInflater inflater = LayoutInflater.from(mContext);
        switch (viewType) {
            case ONE_TYPE:
                View viewOne = inflater.inflate(R.layout.onetype_layout, parent, false);
                return new OneTypeViewHolder(viewOne);
            case TWO_TYPE:
                View viewTwo = inflater.inflate(R.layout.twotype_layout, parent, false);
                return new TwoTypeViewHolder(viewTwo);
        }
        return null;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

创建好ViewHolder后就给ViewHolder上面根据不断地绑定数据:position判断当前的数据Type,根据Type去给viewHolder绑定各自的数据:

 switch (mPosition.get(position)) {
            case ONE_TYPE:

                ((OneTypeViewHolder) holder).header.setBackgroundResource(oneList.get(position).getImageView());
                ((OneTypeViewHolder) holder).name.setText(oneList.get(position).getName());
                ((OneTypeViewHolder) holder).describe.setText(oneList.get(position).getProfessional());
                break;
            case TWO_TYPE:

                int realPos2 = position - twoList.size();
                ((TwoTypeViewHolder)holder).iv_girl.setBackgroundResource(twoList.get(realPos2).getImg());
                ((TwoTypeViewHolder)holder).tv_describe.setText(twoList.get(realPos2).getTitle());

                break;
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

最后,也是最重要的一点,在GridLayoutManager中设置SpanSize,根据Type返回不同的数据所占的列数,如何类型为1,返回要占据你设置显示列数的几分,相当于以你设置的列数为为分母,要返回的是分子:

GridLayoutManager gm = new GridLayoutManager(this, 2);
        gm.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
            @Override
            public int getSpanSize(int position) {
                 switch(adapter.getItemViewType(position)){
                     case 1:

                         return 2;
                     case 2:

                         return 1;
                 }
                return 0;
            }
        });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

ok,就这样实现了RecycleView的两种布局,思路就是这样,如果有三个四个类型的数据相信也是照葫芦画瓢,上面的项目代码已经放在了GitHub上,点击下载,别忘记start啊

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/175017
推荐阅读
相关标签
  

闽ICP备14008679号