根据 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
包含一个元素数组,所有元素类型相同,一些具有更多可选属性,一些还具有嵌套元素。
它基本上描述了组件及其呈现方式
- 全宽行,堆叠 4 个元素
- 一个 2 列网格,这些元素堆叠在两列中
- 全宽行,包含单个元素
这看起来像这样 -
这是一个示例,但其他布局将遵循此 JSON 结构。
在非常高的层次上,我将每个组件构建为 UIView
的子类,并允许它接受某种模型,为显示的每个元素设置数据。它们都将遵守 LayoutComponent
协议并设置了一些标准值。这在这一点上非常简单。
然后我将使用工厂来 'build' 给定类型的组件。
因为一切都是UIView
的子类,我应该没问题。
目前我不确定的是如何处理组件之间的布局。每个组件的内部布局都很简单,因为我可以在需要知道的地方锚定元素,因为我知道每个组件中存在哪些元素。
当涉及到将这些元素的总和锚定到呈现 UIViewController
的 UIView
时,因为布局是动态的,我不知道如何告诉最后一个 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 来绘制内容
我需要创建一个由根据 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
包含一个元素数组,所有元素类型相同,一些具有更多可选属性,一些还具有嵌套元素。
它基本上描述了组件及其呈现方式
- 全宽行,堆叠 4 个元素
- 一个 2 列网格,这些元素堆叠在两列中
- 全宽行,包含单个元素
这看起来像这样 -
这是一个示例,但其他布局将遵循此 JSON 结构。
在非常高的层次上,我将每个组件构建为 UIView
的子类,并允许它接受某种模型,为显示的每个元素设置数据。它们都将遵守 LayoutComponent
协议并设置了一些标准值。这在这一点上非常简单。
然后我将使用工厂来 'build' 给定类型的组件。
因为一切都是UIView
的子类,我应该没问题。
目前我不确定的是如何处理组件之间的布局。每个组件的内部布局都很简单,因为我可以在需要知道的地方锚定元素,因为我知道每个组件中存在哪些元素。
当涉及到将这些元素的总和锚定到呈现 UIViewController
的 UIView
时,因为布局是动态的,我不知道如何告诉最后一个 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 来绘制内容