StackView 布局并排放置(如 zStack)

StackView layout side by side & on Top of each other (like zStack)

我目前有这个界面,我将 MapView 和 UIView 放在彼此之上。 UIView 是我放置图表叠加层的地方(例如:心率)。

当设备处于纵向模式时,这很好。但是,我想在横向模式下探索不同的布局,其中 UIView(HR Chart)和 MapView 并排。

这在 Interface Builder 中可行吗?还是仅在代码中? (我只想使用 UIKit 来更好地支持较低的操作系统)

注意:我在 IB 中尝试过,但似乎无法弄清楚如何获取堆栈,以便 MapView 和 UIView 在纵向模式下彼此重叠。

这是现在的样子。但我想在横向模式下并排显示图表和地图。

编辑以澄清纵向模式下的当前布局和横向模式下的预期结果。 布局看起来如何。

这可以通过在堆栈视图上使用 Trait Variations,在垂直和水平之间更改轴来完成。

考虑一下这种布局 - 我已经为标签提供了背景颜色以帮助可视化:

  • 每个“名称/值”标签集都在垂直堆栈视图中
  • 每“对”“组”——功率/斜率、距离/经过时间、心率/踏频——也在它们自己的垂直堆栈视图中
  • 3 个“对”在水平堆栈视图中

Select RedPairStack 并在“属性检查器”窗格中单击轴左侧的 + 图标:

从该弹出窗口中,将 Width 更改为 Any,将 Height 更改为 Compact,然后单击 Add Variation:

对于新的 hC 变体,select Horizontal:

GreenPairStackBluePairStack 执行相同的操作。

现在,当设备具有常规高度时,这三个堆栈视图将使用垂直轴...在紧凑高度中,它们将使用水平轴。

结果如下:

这是情节提要的来源,因此您可以检查所有内容:https://pastebin.com/dqNp8CcC


编辑 - 评论后...

要获得 side-by-side,我们需要进行一些更改:

看起来很相似,但是:

  • UIView - “PairsContainerView”(哈密瓜背景)
  • 中嵌入了“label/value”水平堆栈
  • 在垂直堆栈视图中嵌入该视图和地图视图

我从 PairStacks 中删除了 Trait 变体,然后将 Horizo​​ntalStack 约束到“PairsContainerView”的所有 4 个边

结果一开始看起来不错,但旋转时标签会被拉长。因此,我们添加了几个新的特征变异。

首先,将所有标签的 Content Hugging Priority 设置为 Required。

接下来,对于 Compact Height (hC) 特性,我们将 CenterY 约束添加到 Horizo​​ntalStack,并删除 Top 和 Bottom 约束。

这是新结果:

并删除颜色:

由于您没有提供您想要您的布局外观的图像,这可能足以让您正在路上。

新故事板来源:https://pastebin.com/TkVbNUVE


编辑 2

从上面的第一个例子开始...

添加一个 UIView 作为地图视图的兄弟并将其自定义 Class 分配给 HeartRateView:

这是我的快速 HeartRateView(红色波浪线):

class HeartRateView: UIView {

    let shapeLayer = CAShapeLayer()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    
    func commonInit() -> Void {
        layer.addSublayer(shapeLayer)
        shapeLayer.strokeColor = UIColor.red.cgColor
        shapeLayer.fillColor = UIColor.clear.cgColor
        shapeLayer.lineWidth = 1.0

        let pth = UIBezierPath()
        let topY: CGFloat = 40.0
        var pt: CGPoint = CGPoint(x: 0.0, y: topY)
        pth.move(to: pt)
        for _ in 1...30 {
            pt.x += 2
            pt.y = topY + CGFloat.random(in: 0...40)
            pth.addLine(to: pt)
        }
        
        shapeLayer.path = pth.cgPath
    }

}

将这些约束添加到 HeartRateView:

  • 顶部等于 MapView 顶部
  • 行距等于 MapView 行距
  • 宽度等于 MapView 宽度
  • 高度等于 MapView 高度

如您所料,这会将 HeartRateView“覆盖”在 MapView 上。

现在,在 Storyboard 中,将 Orientation 切换为 Landscape 并单击“Vary for Traits”按钮。从该弹出窗口中,select Height

Select Document Outline 窗格中的 MapView,以及 Size Inspector 窗格中的 MapView,select Trailing to Safe Area 和 Leading to Heart Rate View 约束:

点击键盘上的删除 - 它将删除此特征变体的约束。应如下所示:

您的视图应如下所示:

Select 心率视图并将其尾部限制在安全区域(我在所有内容上使用 4 点填充)。您的视图现在应该如下所示(心率视图具有清晰的背景,因此我们只能看到 select 离子手柄):

现在添加一个从 MapView Trailing 到 HeartRateView Leading 的约束(4 个用于小填充):

因为HeartRateView仍然被约束为MapView的Equal Width,所以他们会自动填充宽度。

最后一步,点击完成变化

现在我们得到这个输出:

这是第三个故事板来源:https://pastebin.com/2hPXisAH