RecyclerView 与 GirdLayout 一起使用实现动态排版

由于之前做一个小项目的时候其中需要展示一个页面,如图所示:


GIF.gif

遇到这样的需求的时候,我的第一印象就是想用 RecyclerView 的嵌套使用。但是由于 RecyclerView 相互嵌套用在这种情况下比较浪费,况且在相互嵌套的情况下出了一些问题我暂时不知道怎么解决。

所以我用了另外一个方式进行替代:GirdLayout 动态添加 view 。
说到 GirdLayout (网格布局)它是 Android 4.0 以后引入的一个新布局。
其中最重要的两个属性是:

android:layout_columnWeight 
android:layout_rowWeight

其中第一个表示的是列数,也就是总共要分为几列。第二个表示的是行数,也就是说要分成几行。显然,这很符合这个页面的展示要求,但是作为商品的部分展示,我们又不能知道商品的数量,所以我们不能在 xml 里面设置。所以我们需要动态添加 view 。let's do it.

整体思路:
recyclerView + GirdLayout 商品的所有相关信息通过 LayoutInflater 转换为 view ,GirdLayout 动态添加 view ,RecyclerView 实现多个不同类型的商品。

其中涉及两个部分:
1.在添加 view 的时候,View 之中涉及图片大小,由于我们设置列数,由于 Gridlayout 宽度设置 match_parent ,所以整个布局的宽度可以确定。但是如果设置行数的话,那么 Gridlayout 长度设置为 match_parent 的话,那么会对于里面的布局会比较难看,但是如果设置固定的长度,那么对于手机适配这一方面,也会有比较大的差别。所以最好的方法是根据图片的宽度来设置高度。设置方法有多种,其中参考网上觉得最容易的一种是重写 ImageView 方法里面的 onMeasure() 方法。将长度与宽度相互联系。

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, widthMeasureSpec);
    }

这是商品信息的布局文件,RelativeLayout 宽度一定要 match_parent,因为这样才能适应 GirdLayout 在设置列数时能完全占满宽度。SquareView 是重写 onMeasure() 的 ImageView ,由于重写了计算长度的方法,所以 layout_height 可以设置为 0dp ,减少绘制。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

   <com.example.administrator.animationview.SquareView
       android:id="@+id/show_iv_showimg"
       android:layout_width="match_parent"
       android:layout_height="0dp" />

    <LinearLayout
        android:id="@+id/linearLayout_2"
        android:layout_below="@+id/show_iv_showimg"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="2dp">
        <TextView
            android:layout_weight="6"
            android:id="@+id/show_service_tv_serviceNick_2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="12sp"/>
        <TextView
            android:gravity="end"
            android:layout_weight="4"
            android:id="@+id/show_service_tv_servicePrice_2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="14sp"/>
    </LinearLayout>
</RelativeLayout>
  1. 在动态添加 view 的过程, 在 onBindViewHolder() 这个方法中动态添加 view 。
private void addView(ViewHolder viewHolder, final List<MessageBean> messageBeans){
        viewHolder.showMessage.removeAllViews();
        final int columcounts = viewHolder.showMessage.getColumnCount();
        int marginlength = DipUtils.dipTopx(context,6);

        for(int i=0;i<messageBeans.size();i++){
            Log.d("ooo",messageBeans.size()+"");
            GridLayout.Spec rowSpec =  GridLayout.spec(i/columcounts);
            GridLayout.Spec columSpec = GridLayout.spec(i%columcounts,1.0f);

            View view = LayoutInflater.from(viewHolder.showMessage.getContext()).inflate(R.layout.item_gl_show,viewHolder.showMessage,false);
            SquareView squareView = view.findViewById(R.id.show_iv_showimg);
            TextView  nick = view.findViewById(R.id.show_service_tv_serviceNick_2);
            TextView  price = view.findViewById(R.id.show_service_tv_servicePrice_2);
            squareView.setImageResource(messageBeans.get(i).getImg());
            nick.setText(messageBeans.get(i).getNick());
            price.setText(messageBeans.get(i).getPrice());


            final int finalI1 = i;
            squareView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Toast.makeText(context,messageBeans.get(finalI1).getNick()+ finalI1,Toast.LENGTH_SHORT).show();
                }
            });

            GridLayout.LayoutParams layoutParams = new GridLayout.LayoutParams(new ViewGroup.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT));
            layoutParams.rowSpec=rowSpec;
            layoutParams.columnSpec=columSpec;
            layoutParams.setMargins(marginlength, marginlength, marginlength, marginlength);
            viewHolder.showMessage.addView(view, layoutParams);
        }

在这段代码中,getColumnCount() 方法就是获取 xml 文件中 GirdLayout 设置的列数。而其中的 dipTopx() 这个方法是 dp 转化为像素的方法 ,主要是为了之后 GirdLayout 设置 margin 参数 。关于 dp ,px,sp 区别与联系 这篇文章详细讲解,不再细说。
http://blog.csdn.net/zhoujiyu123/article/details/54407719

然后就是 GirdLayout 的 rowSpec/columnSpec 分别表示的是行/列配置对象,这里分别用(除/模)得到子控件的(行/列)索引值。GridLyout 设置需要 LayoutParams 对象 。这里还涉及一个知识点就是 LayoutInflater.inflate 参数问题:
下面链接提供详细参考:
http://blog.csdn.net/u012702547/article/details/52628453
http://blog.csdn.net/runningampH/article/details/51003264

总的来说假如是
inflate(@LayoutRes int resource, @Nullable ViewGroup root,boolean attachToRoot)
三个参数。

  • 假如 root 不为 null ,且 attachToRoot 为 true 的话,那么在父布局 root 中将会添加-这个 resource ,不用再 root.addView() 就已经有该布局。

  • 假如 root 不为 null ,且 attachToRoot 为 false ,那么不会将 resource 添加进去 。但是 resource 中的根布局的参数将会有效,因为 layout_width ,layout_height 都是依赖父布局而存在的。

  • 假如 root 为null,不论 attachToRoot 为 true 还是为 false,显示效果都是一样的。当 root 为 null 表示我不需要将第一个参数所指定的布局添加到任何容器中,同时也表示没有任何容器来来协助第一个参数所指定布局的根节点生成布局参数。那么系统就会为我们默认生成一个LayoutParams,通过 generateDefaultLayoutParams() 方法来生成。

protected LayoutParams generateDefaultLayoutParams() {
    return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
}

而对于两种参数:
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root)

  • root 不为 null ,则与 attachRoot 为 true 情况相同。
  • root 为 null , attchRoot 为 false 或 true 都无关。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345