前言

在app开发中,我们可能会有这样的需求,页面中的某个布局像表格一样,但必须支持动态修改布局。以值得买为例,如下图:


红框区域布局可能需要动态改变,比如我今天显示8个item,明天可能只显示4个item,但是布局都是规则的矩形块。这个要怎么实现呢?

在我们的项目中也有类似的需求,一开始我们是采用WebView去实现,但是WebView毕竟比较重,能用原生实现的当然尽量要用原生去实现。

我苦思冥想,想到了一个另类的实现方式。先看效果:

思路

一般的开发中,json数据只表示内容,不表示布局。而html既表示内容,同时也表示布局,这样html较json数据能表示更丰富的元素,也就是html更加灵活,显示啥完全由服务端控制,当然这样也带来了数据冗余,而且通过html绚烂布局也是比较消耗性能的。

能不能让json既表示内容,又表示布局呢?

当然是可以的,只要服务端和客户端约定某种规则,把布局的相关内容写到json数据中就行,然后客户端遵循相应规则去显示就行。这样用json数据也就能够动态的修改布局了。这也是我实现动态栅格布局的整体思路。

还是以值得买为例。服务端必须告诉客户端该如何显示:一共有几行,每一行该怎么分割。比如把一行分割成两个小块,然后小块里面还可以继续分割。这些信息,是通过json数据来表示的。

以上图为例:
1. 整体分为两行。第一行,分割成两个小块A,B,小块的排列顺序为水平方向,比例为2:3。
* A 小块显示图片a。
* B 小块分割为B1和B2。
* B1 显示图片b1
* B2 继续分割为D和E。排列方向为水平。依此类推。
2. 第二行,分割为4个小块,排列顺序为水平方向,比例为1:1:1:1。

数据结构如下:

{
    "images": [
        {
            "children": [
                {
                    "image": "https://xxxx.png",
                    "weight": 2
                },
                {
                    "children": [
                        {
                            "image": "https://xxxx.png",
                            "weight": 1
                        },
                        {
                            "children": [
                                {
                                    "image": "https://xxxx.png",
                                    "weight": 1 },
                                {
                                    "image": "https://xxxx.png",
                                    "weight": 1 }
                            ],
                            "orientation": "h",
                            "weight": 1
                        }
                    ],
                    "orientation": "v",
                    "weight": 3
                }
            ],
            "height": 312,
            "orientation": "h"
        },
        {
            "children": [
                {
                    "image": "https://xxxx.png",
                    "weight": 1
                },
                {
                    "image": "https://xxxx.png",
                    "weight": 1
                },
                {
                    "image": "https://xxxx.png",
                    "weight": 1
                },
                {
                    "image": "https://xxxx.png",
                    "weight": 1
                }
            ],
            "height": 238,
            "orientation": "h"
        }
    ]
}

数据结构说明:
images 是一个数组,每个元素表示一行。
children 是一个数组,每个元素表示一个小块。如果为null,直接显示图片。否则表示当前小块需要继续分割。客户端需要递归取出children里面的值来做分割(children里面还有children),直到children为null。行是一个特殊的块,它多了一个属性height

height 表示一行的高度。(这里的高度是基于设计稿的,还需要根据分辨率计算最终高度).
orientation表示小块里的子块的排列顺序。v表示垂直,h表示水平。
weight 表示这一小块占据的权重(比例)。
json 层级较深,wtf.

其他

当然,这个方案也有一定的局限性,但是我觉得最重要的是思路。只要客户端和服务端定制某个规则,其实json数据也是可以同时表示内容和布局的,这样就达到动态控制布局的目的。如果采用xml来实现的话,还有点定制html规范的感觉。

另外,想看iOS版实现的可以看iOS一种动态栅格布局方案。这是我同事写的,当我告诉他这个思路后,立马领悟了其中的精华并写了个demo。