在 SwiftUI 中水平居中查看
Center View horizontally in SwiftUI
如何在 HStack
中水平居中 View
(Image
)?我希望按钮左对齐,图像在视图中水平居中。
目前我有这样的结构:
VStack {
HStack {
Button(action: {
print("Tapped")
}, label: {
Image("left-arrow")
.resizable()
.frame(width: 30, height: 30, alignment: .leading)
}).padding(.leading, 20)
Spacer()
Image("twitter-logo")
.resizable()
.frame(width: 30, height: 30, alignment: .center)
}
Spacer()
}
这是给我的:
但是我想实现这个:
如何将按钮大小保存为 属性 并向图像添加负边距?并且注意图片后面多了一个spacer
struct ContentView: View {
var buttonSize: Length = 30
var body: some View {
VStack {
HStack {
Button(action: {
print("Tapped")
}, label: {
Image(systemName: "star")
.resizable()
.frame(width: buttonSize, height: buttonSize, alignment: .leading)
})
Spacer()
Image(systemName: "star")
.resizable()
.frame(width: 30, height: 30, alignment: .center)
.padding(.leading, -buttonSize)
Spacer()
}
Spacer()
}
}
}
结果:
您可以将两个 HStack
嵌入一个 ZStack
中,并根据水平间距放置相应的垫片。将所有内容嵌入 VStack
和 Spacer()
以将所有内容推到顶部。
struct ContentView : View {
var buttonSize: Length = 30
var body: some View {
VStack {
ZStack {
HStack {
Button(action: {
}, label: {
Image(systemName: "star")
.resizable()
.frame(width: CGFloat(30), height: CGFloat(30), alignment: .leading)
}).padding(.leading, CGFloat(20))
Spacer()
}
HStack {
Image(systemName: "star")
.resizable()
.frame(width: CGFloat(30), height: CGFloat(30), alignment: .center)
}
}
Spacer()
}
}
}
注意:在第二个 HStack
中,图像应该自动居中对齐,但如果不是,您可以在图像前后放置一个 Spacer()
。
编辑:添加了 VStack
和 Spacer()
以将所有内容移动到顶部,就像 OP 想要的那样。
编辑 2:删除了图像上的填充,因为它导致图像稍微偏离中心。因为它在它自己的 HStack
和 center-aligned 中,所以不需要填充。
编辑 3:感谢评论中的@Chris Prince,我决定制作一个简单的 NavigationBar-esque 自定义视图,您可以提供左、中、右参数来创建 OP 所需的效果(其中每组视图彼此独立对齐):
struct CustomNavBar<Left, Center, Right>: View where Left: View, Center: View, Right: View {
let left: () -> Left
let center: () -> Center
let right: () -> Right
init(@ViewBuilder left: @escaping () -> Left, @ViewBuilder center: @escaping () -> Center, @ViewBuilder right: @escaping () -> Right) {
self.left = left
self.center = center
self.right = right
}
var body: some View {
ZStack {
HStack {
left()
Spacer()
}
center()
HStack {
Spacer()
right()
}
}
}
}
用法:
struct ContentView: View {
let buttonSize: CGFloat = 30
var body: some View {
VStack {
CustomNavBar(left: {
Button(action: {
print("Tapped")
}, label: {
Image(systemName: "star")
.resizable()
.frame(width: self.buttonSize, height: self.buttonSize, alignment: .leading)
}).padding()
}, center: {
Image(systemName: "star")
.resizable()
.frame(width: 30, height: 30, alignment: .center)
}, right: {
HStack {
Text("Long text here")
Image(systemName: "star")
.resizable()
.frame(width: 30, height: 30, alignment: .center)
.padding(.trailing)
}.foregroundColor(.red)
})
Spacer()
Text("Normal Content")
Spacer()
}
}
}
您使用位置居中视图 属性 试试这个代码
Group{ // container View
Image("twitter-logo")
.resizable()
.frame(width: 30, height: 30, alignment: .center)
}.position(x: UIScreen.main.bounds.width/2)
对我来说最简单的方法:
ZStack(){
HStack{
Image("star").resizable().foregroundColor(.white).frame(width: 50, height: 50)
Spacer()
}
Image("star").resizable().font(.title).foregroundColor(.white).frame(width: 50, height: 50)
}
我有一个替代解决方案。我使用隐藏图像作为占位符。
HStack {
Image("left-arrow").padding()
Spacer()
Image("twitter-logo")
Spacer()
// placeholder to keep layout symmetric
Image("left-arrow").padding().hidden()
}
当然,您可以根据需要将图像替换为按钮或其他视图。
让我提出一个不同的解决方案:
https://gist.github.com/buscarini/122516641cd0ee275dd367786ff2a736
可以这样使用:
HStack {
Color.red
.frame(width: 0, height: 50)
.layoutPriority(1)
GlobalHCenteringView {
Text("Hello, world!")
.lineLimit(1)
.background(Color.green)
}
.background(Color.yellow)
Color.red
.frame(width: 180, height: 50)
.layoutPriority(1)
}
}
如果适合,这将使子视图在屏幕中居中,如果不适合,则保持原样。它目前正在使用 UIScreen,因此它仅适用于 iOS,但您可以轻松地将屏幕或父宽度传递给视图的构造函数,从 GeometryReader 或其他任何东西获取它。
让标题像导航栏一样居中的正确方法:
HStack {
Spacer()
.overlay {
HStack {
Image(systemName: "star")
Spacer()
}
}
Text("Title")
Spacer()
.overlay {
HStack {
Spacer()
Image(systemName: "star")
}
}
}
如何在 HStack
中水平居中 View
(Image
)?我希望按钮左对齐,图像在视图中水平居中。
目前我有这样的结构:
VStack {
HStack {
Button(action: {
print("Tapped")
}, label: {
Image("left-arrow")
.resizable()
.frame(width: 30, height: 30, alignment: .leading)
}).padding(.leading, 20)
Spacer()
Image("twitter-logo")
.resizable()
.frame(width: 30, height: 30, alignment: .center)
}
Spacer()
}
这是给我的:
但是我想实现这个:
如何将按钮大小保存为 属性 并向图像添加负边距?并且注意图片后面多了一个spacer
struct ContentView: View {
var buttonSize: Length = 30
var body: some View {
VStack {
HStack {
Button(action: {
print("Tapped")
}, label: {
Image(systemName: "star")
.resizable()
.frame(width: buttonSize, height: buttonSize, alignment: .leading)
})
Spacer()
Image(systemName: "star")
.resizable()
.frame(width: 30, height: 30, alignment: .center)
.padding(.leading, -buttonSize)
Spacer()
}
Spacer()
}
}
}
结果:
您可以将两个 HStack
嵌入一个 ZStack
中,并根据水平间距放置相应的垫片。将所有内容嵌入 VStack
和 Spacer()
以将所有内容推到顶部。
struct ContentView : View {
var buttonSize: Length = 30
var body: some View {
VStack {
ZStack {
HStack {
Button(action: {
}, label: {
Image(systemName: "star")
.resizable()
.frame(width: CGFloat(30), height: CGFloat(30), alignment: .leading)
}).padding(.leading, CGFloat(20))
Spacer()
}
HStack {
Image(systemName: "star")
.resizable()
.frame(width: CGFloat(30), height: CGFloat(30), alignment: .center)
}
}
Spacer()
}
}
}
注意:在第二个 HStack
中,图像应该自动居中对齐,但如果不是,您可以在图像前后放置一个 Spacer()
。
编辑:添加了 VStack
和 Spacer()
以将所有内容移动到顶部,就像 OP 想要的那样。
编辑 2:删除了图像上的填充,因为它导致图像稍微偏离中心。因为它在它自己的 HStack
和 center-aligned 中,所以不需要填充。
编辑 3:感谢评论中的@Chris Prince,我决定制作一个简单的 NavigationBar-esque 自定义视图,您可以提供左、中、右参数来创建 OP 所需的效果(其中每组视图彼此独立对齐):
struct CustomNavBar<Left, Center, Right>: View where Left: View, Center: View, Right: View {
let left: () -> Left
let center: () -> Center
let right: () -> Right
init(@ViewBuilder left: @escaping () -> Left, @ViewBuilder center: @escaping () -> Center, @ViewBuilder right: @escaping () -> Right) {
self.left = left
self.center = center
self.right = right
}
var body: some View {
ZStack {
HStack {
left()
Spacer()
}
center()
HStack {
Spacer()
right()
}
}
}
}
用法:
struct ContentView: View {
let buttonSize: CGFloat = 30
var body: some View {
VStack {
CustomNavBar(left: {
Button(action: {
print("Tapped")
}, label: {
Image(systemName: "star")
.resizable()
.frame(width: self.buttonSize, height: self.buttonSize, alignment: .leading)
}).padding()
}, center: {
Image(systemName: "star")
.resizable()
.frame(width: 30, height: 30, alignment: .center)
}, right: {
HStack {
Text("Long text here")
Image(systemName: "star")
.resizable()
.frame(width: 30, height: 30, alignment: .center)
.padding(.trailing)
}.foregroundColor(.red)
})
Spacer()
Text("Normal Content")
Spacer()
}
}
}
您使用位置居中视图 属性 试试这个代码
Group{ // container View
Image("twitter-logo")
.resizable()
.frame(width: 30, height: 30, alignment: .center)
}.position(x: UIScreen.main.bounds.width/2)
对我来说最简单的方法:
ZStack(){
HStack{
Image("star").resizable().foregroundColor(.white).frame(width: 50, height: 50)
Spacer()
}
Image("star").resizable().font(.title).foregroundColor(.white).frame(width: 50, height: 50)
}
我有一个替代解决方案。我使用隐藏图像作为占位符。
HStack {
Image("left-arrow").padding()
Spacer()
Image("twitter-logo")
Spacer()
// placeholder to keep layout symmetric
Image("left-arrow").padding().hidden()
}
当然,您可以根据需要将图像替换为按钮或其他视图。
让我提出一个不同的解决方案:
https://gist.github.com/buscarini/122516641cd0ee275dd367786ff2a736
可以这样使用:
HStack {
Color.red
.frame(width: 0, height: 50)
.layoutPriority(1)
GlobalHCenteringView {
Text("Hello, world!")
.lineLimit(1)
.background(Color.green)
}
.background(Color.yellow)
Color.red
.frame(width: 180, height: 50)
.layoutPriority(1)
}
}
如果适合,这将使子视图在屏幕中居中,如果不适合,则保持原样。它目前正在使用 UIScreen,因此它仅适用于 iOS,但您可以轻松地将屏幕或父宽度传递给视图的构造函数,从 GeometryReader 或其他任何东西获取它。
让标题像导航栏一样居中的正确方法:
HStack {
Spacer()
.overlay {
HStack {
Image(systemName: "star")
Spacer()
}
}
Text("Title")
Spacer()
.overlay {
HStack {
Spacer()
Image(systemName: "star")
}
}
}