StackView 布局并排并在彼此之上(如 zStack)
Posted
技术标签:
【中文标题】StackView 布局并排并在彼此之上(如 zStack)【英文标题】:StackView layout side by side & on Top of each other (like zStack) 【发布时间】:2021-01-07 12:35:36 【问题描述】:我目前有这个界面,我将 MapView 和 UIView 放在一起。 UIView 是我放置图表叠加层的位置(例如:心率)。
当设备处于纵向模式时,这很好。但是,我想在横向模式下探索一种不同的布局,即 UIView(HR Chart) 和 MapView 并排。
这在 Interface Builder 中可行吗?还是仅在代码中? (我只想使用 UIKit 更好地支持较低的操作系统)
注意:我在 IB 中尝试过,但似乎无法弄清楚如何获取 Stack 以使 MapView 和 UIView 在纵向模式下相互重叠。
这就是现在的样子。但我想在横向模式下并排显示图表和地图。
编辑以澄清纵向模式下的当前布局和横向模式下的预期结果。 布局的样子。
【问题讨论】:
【参考方案1】:这可以通过在堆栈视图上使用特征变化来完成,在垂直和水平之间更改轴。
考虑一下这个布局 - 我给标签设置了背景颜色来帮助可视化:
每个“名称/值”标签集都位于垂直堆栈视图中 “组”中的每个“对” - 功率/斜率、距离/经过时间、心率/节奏 - 也在各自的垂直堆栈视图中 这 3 个“对”位于水平堆栈视图中选择RedPairStack
,然后在“属性检查器”窗格中,单击轴左侧的+
图标:
从该弹出窗口中,将 Width
更改为 Any
并将 Height
更改为 Compact
并单击 Add Variation
:
对于新的hC
变体,选择Horizontal
:
对GreenPairStack
和BluePairStack
执行相同操作。
现在,当设备具有常规高度时,这三个堆栈视图将使用垂直轴...在紧凑高度中,它们将使用水平轴。
结果如下:
这里是 Storyboard 的来源,因此您可以检查所有内容:https://pastebin.com/dqNp8CcC
编辑 - 在 cmets...
要实现并排,我们需要进行一些更改:
看起来很相似,但是:
在UIView
- “PairsContainerView”(哈密瓜背景)中嵌入了“标签/值”水平堆栈
将该视图和地图视图嵌入垂直堆栈视图中
我从 PairStacks 中删除了 Trait 变体,然后将 HorizontalStack 约束到“PairsContainerView”的所有 4 个边
结果起初看起来不错,但旋转时标签会被拉长。因此,我们添加了几个新的特征变化。
首先,将所有标签的 Content Hugging Priority 设置为Required。
接下来,对于 Compact Height (hC
) 特征,我们将 CenterY 约束添加到 HorizontalStack,并移除 Top 和 Bottom 约束。
以下是新结果:
并去除颜色:
由于您没有提供您希望布局外观的图片,这可能足以让您上路。
新故事板源:https://pastebin.com/TkVbNUVE
编辑 2
从上面的第一个例子开始...
添加一个UIView
作为地图视图的同级并将其自定义类分配给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 高度如您所料,这将“叠加”在 MapView 上的 HeartRateView。
现在,在 Storyboard 中,将 Orientation 切换为 Landscape,然后单击“Vary for Traits”按钮。从该弹出窗口中,选择Height
在 Document Outline 窗格中选择 MapView,然后在 Size Inspector 窗格中选择 Trailing to Safe Area 和 Leading to Heart Rate View 约束:
点击键盘上的删除 - 它会仅删除此 Trait 变体的那些约束。应该是这样的:
你的视图应该是这样的:
选择心率视图并将其尾随限制到安全区域(我在所有内容上都使用 4 点填充)。您的视图现在应该如下所示(心率视图有清晰的背景,所以我们只能看到选择句柄):
现在添加一个从 MapView Trailing 到 HeartRateView Leading 的约束(小填充为 4):
因为 HeartRateView 仍然被限制为 MapView 的 Equal Width,所以它们会自动填充宽度。
最后一步,点击完成变化
现在我们得到这个输出:
这是第三个故事板来源:https://pastebin.com/2hPXisAH
【讨论】:
OP想要实现横向并排的布局,所以我认为地图应该在屏幕的右侧,仪表盘在屏幕的左侧。 @donMag 首先。非常令人印象深刻。我花了几天时间才在横向模式下将功率/斜率等设置为 1 行)正确。 (我对 IB 的仇恨越来越大:-p)。第二,我很抱歉(如果)你花了这么多时间,但我实际上希望“mapView”和“UIView”在横向模式下并排。 (也许而且很可能我的描述不是那么好)。在纵向模式下,MapView 和 UIView(带有 HR 图表)彼此重叠。在横向模式下,我想探索它们并排..(注意:我没有看过你的源代码) @myjunk - 啊,以为你在展示你想要的布局。请参阅我的答案的编辑。 @DonMag - 当我描述心率图 (Uiview) 位于 MapView 顶部(如 zstack)时,我添加了视图的外观图片。 UIView 是透明的,可以绘制用户的心率数据(屏幕截图上那些波浪状的红线)。它与地图视图的大小完全相同。我添加了一个侧视图来显示当前布局。 ?抱歉给您带来了困惑。 @myjunk - 如果您仍在尝试使此布局正常工作...一般的想法是为 HeartRateView 创建 2 个主要约束:一个用于地图可见,一个用于隐藏地图。当地图可见时将“MapVisible”约束设置为更高的优先级,当地图隐藏时将“MapHidden”约束设置为更高的优先级。我在这里放了一个更新的 Storyboard 和相关的 View Controller 代码:gist.github.com/DonMag/1ddc83e04584756ad750855b16a14ba1以上是关于StackView 布局并排并在彼此之上(如 zStack)的主要内容,如果未能解决你的问题,请参考以下文章