StackView 并排布局 &在彼此之上(如 zStack) [英] StackView layout side by side & on Top of each other (like zStack)

查看:23
本文介绍了StackView 并排布局 &在彼此之上(如 zStack)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

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

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

编辑以澄清纵向模式下的当前布局和横向模式下的预期结果.布局的样子.

解决方案

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

考虑这个布局 - 我已经给了标签背景颜色来帮助可视化:

  • 每个名称/值"标签集位于垂直堆栈视图中
  • 每个对"套"- 功率/斜率、距离/经过时间、心率/节奏 - 也在他们自己的垂直堆栈视图中
  • 3 个对"处于水平堆栈视图中

选择 RedPairStack,然后在 Attributes Inspector 窗格中,单击 Axis 左侧的 + 图标:

从该弹出窗口中,将 Width 更改为 Any 并将 Height 更改为 Compact 并单击 Add变化:

对于新的 hC 变体,选择 Horizo​​ntal:

GreenPairStackBluePairStack 执行相同的操作.

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

结果如下:

这是 Storyboard 的源代码,因此您可以检查所有内容:

看起来非常相似,但是:

  • 嵌入了标签/值";UIView 中的水平堆栈 - PairsContainerView"(哈密瓜背景)
  • 在垂直堆栈视图中嵌入该视图和地图视图

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

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

首先,将所有标签上的内容拥抱优先级设置为必需.

接下来,对于 Compact Height (hC) trait,我们向 Horizo​​ntalStack 添加一个 CenterY 约束,并移除顶部和底部约束.

这是新的结果:

并去除颜色:

由于您没有提供您希望布局的外观图像,这可能足以让您顺利上路.

新故事板来源:

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

class HeartRateView: UIView {让 shapeLayer = CAShapeLayer()覆盖初始化(框架:CGRect){super.init(框架:框架)通用初始化()}需要初始化?(编码器:NSCoder){super.init(编码器:编码器)通用初始化()}func commonInit() ->空白 {layer.addSublayer(shapeLayer)shapeLayer.strokeColor = UIColor.red.cgColorshapeLayer.fillColor = UIColor.clear.cgColorshapeLayer.lineWidth = 1.0让 pth = UIBezierPath()让 topY: CGFloat = 40.0var pt: CGPoint = CGPoint(x: 0.0, y: topY)pth.move(到:pt)对于 _ 在 1...30 {pt.x += 2pt.y = topY + CGFloat.random(in: 0...40)pth.addLine(to: pt)}shapeLayer.path = pth.cgPath}}

将这些约束添加到 HeartRateView:

  • Top 等于 MapView Top
  • 领先等于 MapView 领先
  • 宽度等于 MapView 宽度
  • 高度等于 MapView 高度

如您所料,这将覆盖"MapView 上的 HeartRateView.

现在,在 Storyboard 中,将 Orientation 切换为 Landscape,然后单击Vary for Traits";按钮.从该弹出窗口中,选择 Height

在 Document Outline 窗格中选择 MapView,然后在 Size Inspector 窗格中,选择 Trailing to Safe Area 和 Leadership to Heart Rate View 约束:

点击键盘上的删除" - 它将删除针对此 Trait 变体的那些约束.应该是这样的:

您的视图应如下所示:

选择心率视图并将其拖尾限制在安全区域(我在所有内容上都使用 4 pts 填充).您的视图现在应如下所示(Heart Rate View 具有清晰的背景,因此我们只能看到选择手柄):

现在添加从 MapView Trailing 到 HeartRateView Leadership(小填充为 4)的约束:

因为HeartRateView还是被约束Equal Width to MapView,所以自动填充宽度.

最后一步,点击完成更改

现在我们得到这个输出:

这是第三个 Storyboard 源:https://pastebin.com/2hPXisAH

I currently have this interface whereby I am putting a MapView and a UIView on top of each other. The UIView is where I put my chart overlay (eg: Heart Rate).

This is fine when the device is in portrait mode. However, I would like to explore a different layout when in landscape mode whereby the UIView(HR Chart) and the MapView is side by side.

Is this doable in Interface Builder? Or only in code? (I would like to only use UIKit to better support lower OSes)

note : I tried in IB but can't seem to figure out how to get the Stack such that the MapView and UIView is on top of each other in Portrait mode.

This is how it looks like now. But I would like to the Chart and the Map side by side in landscape mode.

Edit for clarification on current layout in portrait mode and desired outcome in landscape mode. How the layout looks like.

解决方案

This can be done by using Trait Variations on stack views, changing the Axis between Vertical and Horizontal.

Consider this layout - I've given the labels background colors to help visualize:

  • Each "name / Value" label set is in a Vertical Stack View
  • Each "Pair" of "sets" - Power / Slope, Distance / Elapsed Time, Heart Rate / Cadence - is also in their own Vertical Stack View
  • The 3 "pairs" are in a Horizontal Stack View

Select the RedPairStack and, in the Attributes Inspector pane, click the + icon to the left of the Axis:

From that popup, change Width to Any and change Height to Compact and click Add Variation:

For the new hC variation, select Horizontal:

Do the same for the GreenPairStack and the BluePairStack.

Now, when the device is has a Regular Height, those three stack views will use a Vertical Axis... in Compact Height, they'll use a Horizontal Axis.

Here's the result:

Here is the source to the Storyboard so you can inspect everything: https://pastebin.com/dqNp8CcC


Edit - after comments...

To get side-by-side, we need a few changes:

Looks very similar, but:

  • embedded the "label/value" horizontal stack in a UIView - "PairsContainerView" (cantaloupe background)
  • embed that view plus the Map view in a Vertical stack view

I removed the Trait variations from the PairStacks, then constrained the HorizontalStack to all 4 sides of the "PairsContainerView"

The result looks good at first, but when rotating the labels get stretched out. So, we add a couple new Trait Variations.

First, set the Content Hugging Priority on all the labels to Required.

Next, for Compact Height (hC) trait, we add a CenterY constraint to the HorizontalStack, and remove the Top and Bottom constraints.

Here's the new results:

and with colors removed:

Since you didn't provide an image of how you want your layout to look, this may be close enough to get you on your way.

New Storyboard souce: https://pastebin.com/TkVbNUVE


Edit 2

Start with the first example above...

Add a UIView as a sibling of the Map View and assign its Custom Class to HeartRateView:

Here's my quick HeartRateView (red squiggly line):

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
    }

}

Add these constraints to HeartRateView:

  • Top equal to MapView Top
  • Leading equal to MapView Leading
  • Width equal to MapView Width
  • Height equal to MapView Height

As you would expect, this will "overlay" the HeartRateView on the MapView.

Now, in Storyboard, switch the Orientation to Landscape and click the "Vary for Traits" button. From that popup, select Height

Select the MapView in the Document Outline pane, and over in the Size Inspector pane, select the Trailing to Safe Area and Leading to Heart Rate View constraints:

Tap Delete on your keyboard - it will delete those constraints only for this Trait variation. Should look like this:

and your view should look like this:

Select the Heart Rate View and constrain its Trailing to the Safe Area (I'm using 4-pts padding on everything). Your view should now look like this (Heart Rate View has a clear background, so we can only see the selection handles):

Now add a constraint from MapView Trailing to HeartRateView Leading (of 4 for the little padding):

Because HeartRateView is still constrained Equal Width to MapView, they automatically fill out the width.

Last step, click Done Varying

Now we get this output:

Here's the third Storyboard source: https://pastebin.com/2hPXisAH

这篇关于StackView 并排布局 &在彼此之上(如 zStack)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆