SwiftUI 如何在 VStack 中垂直居中视图
SwiftUI How to vertically center a view inside a VStack
我想要一个视图在屏幕的垂直中心,一个视图在屏幕顶部,一个视图在这两个视图之间垂直居中,如下所示:
这花了我 5 分钟在故事板上完成,但我似乎没有找到在 SwiftUI 中完成它的方法。
我已经尝试过多个 zstacks、vstacks、多个自定义对齐,但这是我得到的最接近的:
struct SelectionView: View {
var body: some View {
ZStack(alignment: .myAlignment) {
Color.green
.edgesIgnoringSafeArea(.all)
VStack {
Image(systemName: "clock")
.resizable()
.foregroundColor(.white)
.aspectRatio(contentMode: .fit)
.frame(width: 156, height: 80)
// Spacer()
Text("My\nmultiline label")
.multilineTextAlignment(.center)
.font(.title)
.foregroundColor(.white)
// Spacer()
VStack(spacing: 16) {
RoundedRectangle(cornerRadius: 5).fill(Color.white).frame(height: 79)
RoundedRectangle(cornerRadius: 5).fill(Color.white).frame(height: 79)
}
.alignmentGuide(VerticalAlignment.myAlignment) { dimension in
dimension[VerticalAlignment.center]
}
.layoutPriority(1)
}
.padding([.leading, .trailing], 24)
}
}
}
struct SelectionView_Previews: PreviewProvider {
static var previews: some View {
LanguageSelectionView()
}
}
// MARK
extension HorizontalAlignment {
enum MyHorizontal: AlignmentID {
static func defaultValue(in d: ViewDimensions) -> CGFloat
{ d[HorizontalAlignment.center] }
}
static let myAlignment =
HorizontalAlignment(MyHorizontal.self)
}
extension VerticalAlignment {
enum MyVertical: AlignmentID {
static func defaultValue(in d: ViewDimensions) -> CGFloat
{ d[VerticalAlignment.center] }
}
static let myAlignment = VerticalAlignment(MyVertical.self)
}
extension Alignment {
static let myAlignment = Alignment(horizontal: .myAlignment,
vertical: .myAlignment)
}
我将 GeometryReader 保留为最后的手段,因为对于这个看似简单的布局来说,它感觉过于激进了..
我想我正在以某种错误的方式处理这个问题(我脑子里仍然有太多 UIKit/Constraints)..
这是可能的解决方案。用 Xcode 12 / iOS 14
测试
struct SelectionView: View {
var body: some View {
ZStack {
Color.green
.edgesIgnoringSafeArea(.all)
VStack(spacing: 16) {
Color.clear
.overlay(
VStack {
Image(systemName: "clock")
.resizable()
.foregroundColor(.white)
.aspectRatio(contentMode: .fit)
.frame(width: 156, height: 80)
Color.clear
.overlay(
Text("My\nmultiline label")
.multilineTextAlignment(.center)
.font(.title)
.foregroundColor(.white)
)
}
)
RoundedRectangle(cornerRadius: 5).fill(Color.white).frame(height: 79)
RoundedRectangle(cornerRadius: 5).fill(Color.white).frame(height: 79)
Color.clear
}
.padding([.leading, .trailing], 24)
}
}
}
我想要一个视图在屏幕的垂直中心,一个视图在屏幕顶部,一个视图在这两个视图之间垂直居中,如下所示:
这花了我 5 分钟在故事板上完成,但我似乎没有找到在 SwiftUI 中完成它的方法。
我已经尝试过多个 zstacks、vstacks、多个自定义对齐,但这是我得到的最接近的:
struct SelectionView: View {
var body: some View {
ZStack(alignment: .myAlignment) {
Color.green
.edgesIgnoringSafeArea(.all)
VStack {
Image(systemName: "clock")
.resizable()
.foregroundColor(.white)
.aspectRatio(contentMode: .fit)
.frame(width: 156, height: 80)
// Spacer()
Text("My\nmultiline label")
.multilineTextAlignment(.center)
.font(.title)
.foregroundColor(.white)
// Spacer()
VStack(spacing: 16) {
RoundedRectangle(cornerRadius: 5).fill(Color.white).frame(height: 79)
RoundedRectangle(cornerRadius: 5).fill(Color.white).frame(height: 79)
}
.alignmentGuide(VerticalAlignment.myAlignment) { dimension in
dimension[VerticalAlignment.center]
}
.layoutPriority(1)
}
.padding([.leading, .trailing], 24)
}
}
}
struct SelectionView_Previews: PreviewProvider {
static var previews: some View {
LanguageSelectionView()
}
}
// MARK
extension HorizontalAlignment {
enum MyHorizontal: AlignmentID {
static func defaultValue(in d: ViewDimensions) -> CGFloat
{ d[HorizontalAlignment.center] }
}
static let myAlignment =
HorizontalAlignment(MyHorizontal.self)
}
extension VerticalAlignment {
enum MyVertical: AlignmentID {
static func defaultValue(in d: ViewDimensions) -> CGFloat
{ d[VerticalAlignment.center] }
}
static let myAlignment = VerticalAlignment(MyVertical.self)
}
extension Alignment {
static let myAlignment = Alignment(horizontal: .myAlignment,
vertical: .myAlignment)
}
我将 GeometryReader 保留为最后的手段,因为对于这个看似简单的布局来说,它感觉过于激进了..
我想我正在以某种错误的方式处理这个问题(我脑子里仍然有太多 UIKit/Constraints)..
这是可能的解决方案。用 Xcode 12 / iOS 14
测试struct SelectionView: View {
var body: some View {
ZStack {
Color.green
.edgesIgnoringSafeArea(.all)
VStack(spacing: 16) {
Color.clear
.overlay(
VStack {
Image(systemName: "clock")
.resizable()
.foregroundColor(.white)
.aspectRatio(contentMode: .fit)
.frame(width: 156, height: 80)
Color.clear
.overlay(
Text("My\nmultiline label")
.multilineTextAlignment(.center)
.font(.title)
.foregroundColor(.white)
)
}
)
RoundedRectangle(cornerRadius: 5).fill(Color.white).frame(height: 79)
RoundedRectangle(cornerRadius: 5).fill(Color.white).frame(height: 79)
Color.clear
}
.padding([.leading, .trailing], 24)
}
}
}