根据 JSON 响应锚定 UI 元素

Anchoring UI elements based on a JSON response

我需要创建一个由根据 api 响应布置的组件组成的视图层。

假设我有一个 JSON 类似的响应 -

{ 
   "id":"1fbcf51b-1811-405d-ba92-de5110910f83",
   "name":"Gaming day",
   "contentTemplate":{ 
      "id":"300c01c3-747e-4446-8193-c2d633bfa8da",
      "name":"Social Announcement",
      "defaultLayoutId":"article",
      "layouts":[ 
         { 
            "id":"article",
            "body":[ 
               { 
                  "classType":"CONTAINER",
                  "category":"CONTAINER",
                  "type":"FULL_WIDTH",
                  "elements":[ 
                     { 
                        "classType":"TEXT",
                        "category":"INPUT",
                        "type":"TITLE",
                        "fieldId":"title"
                     },
                     { 
                        "classType":"TEXT",
                        "category":"INPUT",
                        "type":"SUMMARY",
                        "fieldId":"subtitle"
                     },
                     { 
                        "classType":"IMAGE",
                        "category":"INPUT",
                        "type":"IMAGE",
                        "fieldId":"mainImage"
                     },
                     { 
                        "classType":"TEXT",
                        "category":"INPUT",
                        "type":"RICH_TEXT",
                        "fieldId":"body"
                     }
                  ]
               },
               { 
                  "classType":"CONTAINER",
                  "category":"CONTAINER",
                  "type":"TWO_COLUMN_GRID",
                  "elements":[ 
                     { 
                        "classType":"IMAGE",
                        "category":"INPUT",
                        "type":"IMAGE",
                        "fieldId":"image1"
                     },
                     { 
                        "classType":"TEXT",
                        "category":"INPUT",
                        "type":"RICH_TEXT",
                        "fieldId":"body1"
                     },
                     { 
                        "classType":"TEXT",
                        "category":"INPUT",
                        "type":"RICH_TEXT",
                        "fieldId":"body2"
                     },
                     { 
                        "classType":"IMAGE",
                        "category":"INPUT",
                        "type":"IMAGE",
                        "fieldId":"image2"
                     }
                  ]
               },
               { 
                  "classType":"CONTAINER",
                  "category":"CONTAINER",
                  "type":"FULL_WIDTH",
                  "elements":[ 
                     { 
                        "classType":"METADATA",
                        "category":"METADATA",
                        "type":"RELATED_ARTICLES"
                     }
                  ]
               }
            ]
         }
      ]
   }
}

在这里您可以看到 layouts 包含一个元素数组,所有元素类型相同,一些具有更多可选属性,一些还具有嵌套元素。

它基本上描述了组件及其呈现方式

  1. 全宽行,堆叠 4 个元素
  2. 一个 2 列网格,这些元素堆叠在两列中
  3. 全宽行,包含单个元素

这看起来像这样 -

这是一个示例,但其他布局将遵循此 JSON 结构。

在非常高的层次上,我将每个组件构建为 UIView 的子类,并允许它接受某种模型,为显示的每个元素设置数据。它们都将遵守 LayoutComponent 协议并设置了一些标准值。这在这一点上非常简单。

然后我将使用工厂来 'build' 给定类型的组件。

因为一切都是UIView的子类,我应该没问题。

目前我不确定的是如何处理组件之间的布局。每个组件的内部布局都很简单,因为我可以在需要知道的地方锚定元素,因为我知道每个组件中存在哪些元素。

当涉及到将这些元素的总和锚定到呈现 UIViewControllerUIView 时,因为布局是动态的,我不知道如何告诉最后一个 FULL_WIDTH 元素锚定到底部,之前的元素锚定到它的底部到它的顶部等。

如果感觉我可能会得到大量 if 语句和自动布局代码。

只要每个子元素都有固有的内容大小或堆栈方向的约束(水平堆栈的宽度和垂直堆栈的高度),UIStackView 就会为您执行此操作。

整个东西应该是一个垂直堆栈视图,每一行应该是一个水平堆栈视图。如果您认为它会比屏幕大,那么将它放在滚动视图中,并将垂直堆栈锚定到 contentLayoutGuide,其宽度约束等于 scrollViews 父级;然后它只会垂直滚动它太大而无法显示。

Apple 的堆栈视图指南:https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/LayoutUsingStackViews.html

我建议您使用 UICollectionView 来完成这项任务。 这样class实现了单元格的复用,显示列表时不会占用大量内存

您需要像 ImageCell、TextCell 和其他元素这样的单元格。此单元格应绘制指定大小的内容(使用 sizeThatFits 和 layoutSubviews 或自动布局)

要实现一些布局规则,您有两种可能的方法:

1) 创建自定义 UICollectionViewLayout,doc from Apple

2) 另一种方法是创建布局单元格,如 TwoColumnCell、FullWidthCell。并添加元素单元格,如用于布局单元格的子视图。

第二种方法中断了单元格的重用,因为您不能将单元格重用为具体的元素类型。 你可以基于 UIView 实现这种方式,而不是 UICollectionView。想法是用很少的单元格 classes 进行布局,用很少的 classes 来绘制内容