iOS一种动态栅格布局方案

作者: PURE蓝胖子 | 来源:发表于2017-06-10 20:18 被阅读2389次

    前言

    在日常开发过程中,我们会遇到一些需要不定期动态改变布局的页面或视图块,下面用张图展示一下:

    zdm_home.png
    我以这张图解释一下需求,图上的几块都是需要显示不同的功能模块,点击的时候也需要跳转到不同页面。这个布局实现很简单,但是如果这个布局需要不定期的更改,比如A换到右边,大小发生变化等不确定因素,我们不可能就发布一个新的版本去修改这个页面。所以大部分人会选择webView来实现,或者事先约定好几种布局格式,由后台来随时改变布局。

    解决思路

    事实上这一块并占不了整个页面,大部分情况下只是在tableView中嵌套一截这样的需求,我公司项目的实现用的一直是webView来实现,但是这样就会有很多不必要的问题,比如webView的高度计算,如果客户端来计算高度,在一些网络不稳定情况下,webView的资源没有加载完全,高度就会出现偏差,而且webView的加载速度,性能,和js的交互都是很不理想的。(总之,我大原生就是不爱用h5啦)
    这里其实有两种解决方案

    • 方案1:和后台约定好几种布局样式,客户端根据后台参数来动态显示。
    • 方案2:这块视图看为一个整体,根据json数据将其分为X个子块,理论上可以根据数据无限分割下去。

    优缺点
    第一种方案实现简单,而且可以应付日常所需,但是提前约定的格式必定不会太多,不够灵活。
    第二种方案完全根据数据决定布局,子块可以无限分割下去,布局灵活,但是数据比较复杂。
    实际上第二种布局是最近公司安卓小哥想出来 一个思路,我和他分别实现了一下,发现效果很好。这里是安卓小哥的简书

    具体实现

    下面来和大家说一下具体的实现思路:

    zdm_home.png

    我们还是以这张图为例:
    1、我们首先定义两个rowitem元素,分别对应行和块的概念。如上图分为两行,A那里代表一整行,下面的四小块代表一整行。分割为row1row2
    2、row1:分割为AB两块,水平排列,宽度比2:3

    • A不用再分,直接显示图片
    • B分为B1、B2两块,垂直排列,高度比1:1
    • B2分为D、E两块,水平排列,宽度比1:1
      row2:分割为1:1:1:1的四小块

    json数据的结构如下:

    {
        "images": [
            {
                "children": [
                    {
                        "image": "https://i.huim.com/miaoquan/14966511524892.SS2!/both/300x300/unsharp/true",
                        "weight": 2
                    },
                    {
                        "children": [
                            {
                                "image": "https://i.huim.com/miaoquan/14963170206106.jpg!/both/300x300/unsharp/true",
                                "weight": 1
                            },
                            {
                                "children": [
                                    {
                                        "image": "https://i.huim.com/miaoquan/14968041079523.jpg!/compress/true/both/300x300",
                                        "weight": 1
                                    },
                                    {
                                        "image": "https://i.huim.com/miaoquan/14968026112335.jpg!/compress/true/both/300x300",
                                        "weight": 1
                                    }
                                ],
                                "orientation": "h",
                                "weight": 1
                            }
                        ],
                        "orientation": "v",
                        "weight": 3
                    }
                ],
                "height": 212,
                "orientation": "h"
            },
            {
                "children": [
                    {
                        "image": "https://i.huim.com/miaoquan/14929203253142.SS2!/both/300x300/unsharp/true",
                        "weight": 1
                    },
                    {
                        "image": "https://i.huim.com/contents/14828912708690.jpg!/both/300x300/unsharp/true",
                        "weight": 1
                    },
                    {
                        "image": "https://i.huim.com/miaoquan/14968146185109.jpg!/both/300x300/unsharp/true",
                        "weight": 1
                    },
                    {
                        "image": "https://i.huim.com/miaoquan/14968145059484.jpg!/both/300x300/unsharp/true",
                        "weight": 1
                    }
                ],
                "height": 138,
                "orientation": "h"
            }
        ]
    }
    
    

    数据说明:
    images:数组,数组的元素个数决定了整个View需要分为几行row
    children:数组,数组元素个数决定了每个row需要分为多少个块item
    heightrow的高度
    orientation:布局方向,vh,分别对应垂直和水平方向
    image:该子块显示的图片
    weight:在这一块中的权重比

    最重要的是对这个数据的处理,children代表了块,这里用到了递归的思想,只要这一层的数据有children,就需要一直分割下去,直到children为null,停止分割,显示图片。这里的数据层次较深,逻辑需要处理清晰。

    不得不说,安卓小哥的当时提出了这个思路吸引到了我,和他分别实现了过后发现十分好用。这刚好解决了我公司项目中遇到的问题,如果衍生出去,其实可以代替很多地方的布局方式。这种布局灵活度很高,完全由后端数据控制,是个很棒的想法。

    下面展示一下我实现的效果图:

    FSGridLayoutDemo.gif

    上面的边框线是我方便区分每一块加上的,实际开发可以忽略。若果需要每个子块的跳转信息,可以在image那一层加一个参数。比如我公司是定义了一个页面跳转协议,客户端,前端,后端都是遵循这个协议,我举个例子,加了一个跳转参数"pushurl":"huim://detail?id=1234",我就知道这块需要跳转到商品id为1234的详情页。实现了高度动态化布局和跳转。我也不知道该称之为什么布局,所以暂时称之为栅格化布局

    局限性

    这个布局正如我文章所述,一般是用来实现那种轻量级的页面,我主要是用来替代那种嵌套的webView的,如果太过复杂的页面当然就没有这个必要了。当然可以衍生出去可能会有适合你自己项目的地方。所以,酌情使用吧。

    我写的demo在这里,想要看具体实现的可以前往下载,欢迎提出更好的实现方式。

    如果对你有所帮助和启发,不妨点个喜欢

    68fc9e97e32f8d394891bde8424dfac5.png

    相关文章

      网友评论

      • jgyhc:第二种好是好,对于数据录入的人来说没那么傻瓜化了~:flushed:
      • 动感超人丶:期待后台cms设计思路
      • 欧阳大哥2013:您好,作者。根据你这边提供的一个栅格的思维,我在我的界面布局库中添加了一种全新的栅格布局MyGridLayout。专门用来解决你的这种需求。你可以到如下地址:

        https://github.com/youngsoft/MyLinearLayout 中的关于栅格布局的DEMO中的一些介绍。

        以及 http://bicyclering.com/2017/09/01/layout/ 中介绍栅格布局的原理和实现的。
        李有钱灬:我看你的文章已经中毒了,根本停不下来呀😂
        PURE蓝胖子:@欧阳大哥2013 :+1:
      • 透亮心情:我现在就是这种需求,但是没有返回高度,高度要根据返回图片高度自适应,坑死我了!
        PURE蓝胖子:@透亮心情 这个应该跟后台约定一下比较好
        透亮心情:@PURE蓝胖子 对,我现在就是先获取图片高度,在赋值!然后你这个后台数据约束的很好,我这个就坑了!我这个是数据没分层,直接返回。然后我移动端先定义几种固定布局,根据返回的type来创建!:joy:
        PURE蓝胖子:你可以拿到数据后自己计算出图片高度后再封装进去 就是麻烦点
      • 小胖学前端:楼主,安卓小哥没写吗?
        leandom:安卓小哥写的在这里:https://github.com/leandom/SimpleGridLayout
      • HelloYeah:试着结合collectionView 使用,自定义layout布局。我也写了一个demo实现这种效果,用collectionView实现的,思路是你这里的方案一,做不到灵活适配后台数据,demo也还有一些问题没解决 。collectionView 结合方案二使用,应该是比较理想的方案。可以试着写一下,个人觉得有点难度。可以互相交流一下。
        HelloYeah:@PURE蓝胖子 https://github.com/HelloYeah/OnlineMart 我写的demo。还不完善。
        PURE蓝胖子:@HelloYeah 其实这种需求一开始想到的都是collectionView,我这个因为是结合项目需求想出来的一个替代方法,本身我是要把这个嵌套进tableView上的,而且是个比较轻量级的方式,如果用collectionView可能逻辑关系会比较复杂,我也是觉得不太好实现所以没用,有时间我会再尝试实现一下,不过如果你要实现比较复杂的页面的话,其实阿里的lazyscrollView和它衍生出来的tangram应该更适合,因为页面太复杂的话,json数据也会变得庞大。欢迎交流,邮箱联系更及时fengshun_ios@126.com
      • 施主小欣:谢谢楼主大大提供思路~ 感谢分享!
        PURE蓝胖子:@施主小欣 :kissing_heart:
      • 面皮大师:我准备运用到项目里面去,不错!
        PURE蓝胖子:很高兴对你有所帮助,如果需要运用到项目中,应该根据实际情况做适量修改。这里提出的方案是以我们的项目为例。另外,我们也是准备下个版本实际运用呢:grin:
      • 面皮大师:思路不错
      • XueYongWei:思路不错,赞一个

      本文标题:iOS一种动态栅格布局方案

      本文链接:https://www.haomeiwen.com/subject/bvlcqxtx.html