这是一个分割。
我有一个包含 2 个 vstack 的 zstack。
第一个 vstack 有一个间隔符和一个图像 第二个有文本和按钮。
ZStack {
VStack {
Spacer()
Image("some image")
}
VStack {
Text("press the button")
Button("ok") {
print("you pressed the button")
}
}
}
现在,这个设置可以轻松地在 zstack 底部提供一个图像,以及居中的标题和按钮。
但是,例如,如果设备的屏幕较小或 ipad 旋转为横向。取决于图像大小(动态)。标题和按钮将与图像重叠。而不是按钮被“推”起来。
在 UIKit 中,这很简单,只需将按钮居中以具有高优先级的 super View ,并使用具有所需优先级的 GreaterThanOrEqualTo image.topAnchor 即可。
按钮将在屏幕居中,但如果图像顶部太大,中心约束将优先考虑图像顶部 anchor 所需的约束,并将按钮向上推。
我研究了自定义对齐方式,并且可以轻松地始终位于图像上方或始终居中,但缺少一些根据布局来实现两者的见解。图像尺寸是动态的,因此没有硬编码尺寸。
我在这里缺少什么?你将如何解决这个简单但棘手的任务。
最佳答案
使用.alignmentGuide
可能有一种更简单的方法,但我尝试在Layout
上练习以获得这个答案。
我创建了一个自定义的ImageAndButtonLayout
,它应该执行您想要的操作:它需要两个 View ,假设第一个是图像,第二个是按钮(或其他任何内容)。
为了清晰起见,将它们放入 subview 中,您也可以将它们直接放入ImageAndButtonLayout
中。为了进行测试,您可以通过 slider 更改图像的高度。
布局始终使用可用的完整高度并将第一个 View (图像)推到底部 - 因此您不需要对图像使用额外的 Spacer()
。第二个 View (按钮)的位置是根据第一个 View 的高度和可用高度计算的。
struct ContentView: View {
@State private var imageHeight = 200.0 // for testing
var body: some View {
VStack {
ImageAndButtonLayout {
imageView
buttonView
}
// changing "image" height for testing
Slider(value: $imageHeight, in: 50...1000)
.padding()
}
}
var imageView: some View {
Color.teal // Image placeholder
.frame(height: imageHeight)
}
var buttonView: some View {
VStack {
Text("press the button")
Button("ok") {
print("you pressed the button")
}
}
}
}
struct ImageAndButtonLayout: Layout {
func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
let maxsizes = subviews.map { $0.sizeThatFits(.infinity) }
var totalWidth = maxsizes.max {$0.width < $1.width}?.width ?? 0
totalWidth = min(totalWidth, proposal.width ?? .infinity )
let totalHeight = proposal.height ?? .infinity // always return maximum height
return CGSize(width: totalWidth, height: totalHeight)
}
func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
let heightImage = subviews.first?.sizeThatFits(.unspecified).height ?? 0
let heightButton = subviews.last?.sizeThatFits(.unspecified).height ?? 0
let maxHeightContent = bounds.height
// place image at bottom, growing upwards
let ptBottom = CGPoint(x: bounds.midX, y: bounds.maxY) // bottom of screen
if let first = subviews.first {
var totalWidth = first.sizeThatFits(.infinity).width
totalWidth = min(totalWidth, proposal.width ?? .infinity )
first.place(at: ptBottom, anchor: .bottom, proposal: .init(width: totalWidth, height: maxHeightContent))
}
// place button at center – or above image
var centerY = bounds.midY
if heightImage > maxHeightContent / 2 - heightButton {
centerY = maxHeightContent - heightImage
centerY = max ( heightButton * 2 , centerY ) // stop at top of screen
}
let ptCenter = CGPoint(x: bounds.midX, y: centerY)
if let last = subviews.last {
last.place(at: ptCenter, anchor: .center, proposal: .unspecified)
}
}
}
关于SwiftUI 居中对齐 View ,除非另一个 View "pushes"将其向上,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75457887/