SwiftUI:将视图与 VStack 中另一个视图的前缘和后缘对齐
SwiftUI: Aligning views to the leading & trailing edges of another view in a VStack
如何在 SwiftUI 中将内容与另一个视图的前缘和后缘对齐VStack
?
我目前有以下 SwiftUI 代码:
struct MyBlock: View {
var body: some View {
Rectangle().foregroundColor(.gray).frame(width: 80, height: 80)
}
}
struct MyGridView: View {
var body: some View {
HStack(spacing: 16) {
MyBlock()
MyBlock()
MyBlock()
}
}
}
struct PinPad: View {
var body: some View {
VStack {
MyGridView()
HStack {
Button(action: {}, label: { Text("Left Align") })
Spacer()
Button(action: {}, label: { Text("Right Align") })
}
}
}
}
结果呈现如下:
但我真正想要的是 "Left Align"
Button
与 MyGridView
的 left/leading 边缘和 "Right Align"
Button
对齐] 对齐 MyGridView
的 right/trailing 边缘。
例如,像这样:
我显然在这里遗漏了一些非常基本的东西,因为在 UIKit 中使用自动布局执行此操作是微不足道的。
解决布局问题需要做的第一件事是在视图上添加边框。这将使您看到视图的真实(和不可见)范围。问题会更加清晰:
在您的情况下,可以通过将其全部包裹在 HStack 中并添加一些垫片来轻松修复它:
struct PinPad: View {
var body: some View {
HStack {
Spacer()
VStack {
MyGridView().border(Color.blue, width: 3)
HStack {
Button(action: {}, label: { Text("Left Align") }).border(Color.red, width: 3)
Spacer()
Button(action: {}, label: { Text("Right Align") }).border(Color.red, width: 3)
}
}.border(Color.green, width: 3)
Spacer()
}
}
}
GeometryReader
是一个视图,可让您访问父项的大小和位置
定义了一个名为 GeometryGetter 的视图,
struct GeometryGetter: View {
@Binding var rect: CGRect
var body: some View {
return GeometryReader { geometry in
self.makeView(geometry: geometry)
}
}
func makeView(geometry: GeometryProxy) -> some View {
DispatchQueue.main.async {
self.rect = geometry.frame(in: .global)
}
return Rectangle().fill(Color.clear)
}
}
然后如下更改代码,
struct PinPad: View {
@State private var rect: CGRect = CGRect()
var body: some View {
HStack {
VStack {
MyGridView().background(GeometryGetter(rect: $rect))
HStack {
Button(action: {}, label: { Text("Left Align") })
Spacer()
Button(action: {}, label: { Text("Right Align") })
}.frame(width: rect.width)
}
}
}
}
您可以在 VStack 之后添加 .fixedSize()。
将 .fixedSize()
添加到您的 VStack 即可解决问题。
struct PinPad: View {
var body: some View {
VStack {
MyGridView()
HStack {
Button(action: {}, label: { Text("Left Align") })
Spacer()
Button(action: {}, label: { Text("Right Align") })
}
}
.fixedSize()
}
}
简要说明:
Basic thing about autolayout, in swiftui depends upon the frame of
different stack of Stacks we use. As in this query, first VStack is
the parent view, which wrapped around its childView for its frame as
it is explicitly provided. But, due to the HStack of buttons which
doesn't have any explicitly width provided but due to the Spacer()
;
(which explicitly made the buttons drag to their edges), HStack's
frame had width of size of screen available, which made the parent
VStack view to get enlarged as well along with it. Thus, we need to
pay attention to the sub-views frame as well, along with the parent
view.
Extra info:- Adding alignment:
to the stacks itself will only align the content within that view, while adding .frame(alignment:)
modifier will align the view itself.
如何在 SwiftUI 中将内容与另一个视图的前缘和后缘对齐VStack
?
我目前有以下 SwiftUI 代码:
struct MyBlock: View {
var body: some View {
Rectangle().foregroundColor(.gray).frame(width: 80, height: 80)
}
}
struct MyGridView: View {
var body: some View {
HStack(spacing: 16) {
MyBlock()
MyBlock()
MyBlock()
}
}
}
struct PinPad: View {
var body: some View {
VStack {
MyGridView()
HStack {
Button(action: {}, label: { Text("Left Align") })
Spacer()
Button(action: {}, label: { Text("Right Align") })
}
}
}
}
结果呈现如下:
但我真正想要的是 "Left Align"
Button
与 MyGridView
的 left/leading 边缘和 "Right Align"
Button
对齐] 对齐 MyGridView
的 right/trailing 边缘。
例如,像这样:
我显然在这里遗漏了一些非常基本的东西,因为在 UIKit 中使用自动布局执行此操作是微不足道的。
解决布局问题需要做的第一件事是在视图上添加边框。这将使您看到视图的真实(和不可见)范围。问题会更加清晰:
在您的情况下,可以通过将其全部包裹在 HStack 中并添加一些垫片来轻松修复它:
struct PinPad: View {
var body: some View {
HStack {
Spacer()
VStack {
MyGridView().border(Color.blue, width: 3)
HStack {
Button(action: {}, label: { Text("Left Align") }).border(Color.red, width: 3)
Spacer()
Button(action: {}, label: { Text("Right Align") }).border(Color.red, width: 3)
}
}.border(Color.green, width: 3)
Spacer()
}
}
}
GeometryReader
是一个视图,可让您访问父项的大小和位置
定义了一个名为 GeometryGetter 的视图,
struct GeometryGetter: View {
@Binding var rect: CGRect
var body: some View {
return GeometryReader { geometry in
self.makeView(geometry: geometry)
}
}
func makeView(geometry: GeometryProxy) -> some View {
DispatchQueue.main.async {
self.rect = geometry.frame(in: .global)
}
return Rectangle().fill(Color.clear)
}
}
然后如下更改代码,
struct PinPad: View {
@State private var rect: CGRect = CGRect()
var body: some View {
HStack {
VStack {
MyGridView().background(GeometryGetter(rect: $rect))
HStack {
Button(action: {}, label: { Text("Left Align") })
Spacer()
Button(action: {}, label: { Text("Right Align") })
}.frame(width: rect.width)
}
}
}
}
您可以在 VStack 之后添加 .fixedSize()。
将 .fixedSize()
添加到您的 VStack 即可解决问题。
struct PinPad: View {
var body: some View {
VStack {
MyGridView()
HStack {
Button(action: {}, label: { Text("Left Align") })
Spacer()
Button(action: {}, label: { Text("Right Align") })
}
}
.fixedSize()
}
}
简要说明:
Basic thing about autolayout, in swiftui depends upon the frame of different stack of Stacks we use. As in this query, first VStack is the parent view, which wrapped around its childView for its frame as it is explicitly provided. But, due to the HStack of buttons which doesn't have any explicitly width provided but due to the
Spacer()
; (which explicitly made the buttons drag to their edges), HStack's frame had width of size of screen available, which made the parent VStack view to get enlarged as well along with it. Thus, we need to pay attention to the sub-views frame as well, along with the parent view.Extra info:- Adding
alignment:
to the stacks itself will only align the content within that view, while adding.frame(alignment:)
modifier will align the view itself.