使用 AutoLayout 在 UIView 中定位百分比定位的子视图

Use AutoLayout to position percentage-positioned subviews inside UIView

我正在与一些 JSON 合作,它们为我提供了一系列视图和子视图以在 UIView 中进行布局,我想使用 AutoLayout 来实现它。这是 JSON:

的示例
"component": {
    "width": 150,
    "height": 100,
    "elements": [
        {
            "x": 0.1,
            "y": 0.1,
            "w": 0.8,
            "h": 0.8
        }   
    ]
}

在此示例中,外部视图(component 视图)要求尺寸为 150 x 100。我已经根据屏幕宽度设置了保持宽高比的布局,如下所示:

private func fittedSize(for dimensions: Dimensions) -> CGSize {
    var width: CGFloat
    var height: CGFloat

    if dimensions.width.value > dimensions.height.value {
        let aspectRatio = dimensions.height.value / dimensions.width.value
        width = dimensions.width.value
        height = dimensions.width.value * aspectRatio
    } else {
        let aspectRatio = dimensions.width.value / dimensions.height.value
        height = dimensions.height.value
        width = dimensions.height.value * aspectRatio


    let apertureSize = CGSize(width: width, height: height)

    if apertureSize.width > apertureSize.height {
        let scale = bounds.width / apertureSize.width
        return CGSize(width: apertureSize.width * scale, height: apertureSize.height * scale)
    } else {
        let scale = bounds.height / apertureSize.height
        return CGSize(width: apertureSize.width * scale, height: apertureSize.height * scale)
    }
}

上述函数计算视图在保持其尺寸指定的宽高比的同时可以达到的最大尺寸,例如,在屏幕宽度为 320 时,100x150 的视图将为 320x480。

我现在需要布置该视图的子视图,其中包含该组件中的元素。这些值指定为百分比,因此在上面的示例中,元素应位于左侧和顶部宽度的 10%,以及父视图宽度和高度的 80%。

我可以使用带乘数的约束轻松获得正确的宽度和高度,如下所示:

let w = elementView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: element.position.width)
let h = elementView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: element.position.height)

这将采用 0.8,并使子视图成为其父级宽度和高度的 80%。问题在于我还想为其位置(x 和 y)使用乘数。 AutoLayout 不支持这个,这就是我要找的答案。

如何使用百分比值在另一个 UIView 中定位和调整大小,使用 AutoLayout 而不是诉诸手动定位框架?

备注:

这是当前布局的示例。红色区域是子视图,浅蓝色区域是父视图。请注意,子视图的大小是正确的,宽度和高度的 80%,但它没有显示从顶部和左侧进入的 10%,这就是我所缺少的。

您还需要给出顶部和左侧约束。 如下所示

elementView.topAnchor.constraint(equalTo: view.topAnchor, constant: height / 10),
elementView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: width / 10),

您可以使用 UILayoutGuide 或虚拟视图,限制父视图的前缘和您的视图的前缘,并使用乘数将此“间隔”视图宽度限制为其父视图宽度。

let l = view.leadingAnchor.constraint(equalTo: view.leadingSpacer.leadingAnchor)
let w = leadingSpacer.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: element.position.x)
let t = leadingSpacer.trailingAnchor.constraint(to: elementView.leadingAnchor)

并激活这个约束

并对顶部垫片做类似的事情。 我已经为这个问题使用了虚拟视图,但是 UILayoutGuide 被提议作为更有效的解决方案,因为它只与 AutoLayout 引擎交互并且不参与渲染。希望这有帮助。