水平堆叠内的中心项目
Center Item Inside Horizontal Stack
如果水平堆栈中有 3 个项目,我想我可以这样做:
HStack{
Text("test")
Spacer()
item2()
Spacer()
Text("test")
}
使 item2() 在两个文本视图之间居中。然而,这个问题是 item2() 不一定总是居中,因为,假设 Text("test") 更改为 Text("a") 或其他东西。这会导致问题,第二项并不总是位于屏幕中央。
如何使 item2() 始终居中?
谢谢
您可能需要添加一些自定义的对齐组件。
extension HorizontalAlignment {
private enum MyHAlignment: AlignmentID {
static func defaultValue(in d: ViewDimensions) -> CGFloat {
return d[HorizontalAlignment.center]
}
}
static let myhAlignment = HorizontalAlignment(MyHAlignment.self)
}
HStack {
Spacer()
Text("jjjjjjjjjj")
Spacer()
Image("image").alignmentGuide(.myhAlignment) { (ViewDimensions) -> CGFloat in
return ViewDimensions[HorizontalAlignment.center]
}
Spacer()
Text("test")
}
.frame(alignment: Alignment(horizontal: .myhAlignment, vertical: .center))
我会建议以下起点(最简单的情况...阅读下面的原因)
正如所见,它确实提供了居中的 w/o 帧偏移和正确对齐的边元素,但是......有 缺点 - 它可以在这种最简单的变体中工作仅 如果事先知道那些 三个文本元素在用户 运行 时间内不应重叠。如果是这种情况(真的有这种情况),那么这种方法就可以了。但是,如果 left/right 文本可能会在 运行 时间内增长,那么将需要更多的计算来将它们的宽度限制为 .frame(maxWidth:)
,具体取决于居中元素的宽度...该变体更复杂, 但这是可行的。
var body: some View {
ZStack {
HStack {
Text("Longer side")
Spacer()
Text("One")
}
item2()
}
}
private func item2() -> some View {
Text("CENTER")
.background(Color.yellow)
.border(Color.red)
}
更新: 这是一种可能的方法,可以限制其中一侧不与居中的一侧重叠(包含异步更新,因此应在 实时预览 或模拟器)
所以...如果左侧文本是动态的并且需要剪切尾随符号,那么它可以这样...
它会自动适应设备方向的变化
struct TestHorizontalPinCenter: View {
@State var centerFrame: CGRect = .zero
private let kSpacing: CGFloat = 4.0
var body: some View {
ZStack {
HStack {
Text("Longer side very long text to fit")
.lineLimit(1)
.frame(maxWidth: (centerFrame == .zero ? .infinity : centerFrame.minX - kSpacing), alignment: .leading)
Spacer()
Text("One")
}
item2()
.background(rectReader($centerFrame))
}
}
private func item2() -> some View {
Text("CENTER")
.background(Color.yellow)
.border(Color.red)
}
func rectReader(_ binding: Binding<CGRect>) -> some View {
return GeometryReader { (geometry) -> AnyView in
let rect = geometry.frame(in: .global)
DispatchQueue.main.async {
binding.wrappedValue = rect
}
return AnyView(Rectangle().fill(Color.clear))
}
}
}
而如果需要左侧包裹,则.lineLimit(nil)
需要额外的布局,解决方案增长,但思路是一样的。希望这会对某人有所帮助。
要使视图居中,您可以使用 ZStack:
ZStack {
item2()
HStack {
Text("test")
Spacer()
Text("test")
}
}
我遇到了同样的问题,@Asperi 的解决方案有效,但我遇到了多行文本问题,如果我在列表中使用它,还会出现一些性能问题。
以下解决方案解决了所有问题。
HStack(alignment: .center) {
Text("test")
.frame(maxWidth: .infinity)
item2()
Text("test")
.frame(maxWidth: .infinity)
}
如果水平堆栈中有 3 个项目,我想我可以这样做:
HStack{
Text("test")
Spacer()
item2()
Spacer()
Text("test")
}
使 item2() 在两个文本视图之间居中。然而,这个问题是 item2() 不一定总是居中,因为,假设 Text("test") 更改为 Text("a") 或其他东西。这会导致问题,第二项并不总是位于屏幕中央。
如何使 item2() 始终居中?
谢谢
您可能需要添加一些自定义的对齐组件。
extension HorizontalAlignment {
private enum MyHAlignment: AlignmentID {
static func defaultValue(in d: ViewDimensions) -> CGFloat {
return d[HorizontalAlignment.center]
}
}
static let myhAlignment = HorizontalAlignment(MyHAlignment.self)
}
HStack {
Spacer()
Text("jjjjjjjjjj")
Spacer()
Image("image").alignmentGuide(.myhAlignment) { (ViewDimensions) -> CGFloat in
return ViewDimensions[HorizontalAlignment.center]
}
Spacer()
Text("test")
}
.frame(alignment: Alignment(horizontal: .myhAlignment, vertical: .center))
我会建议以下起点(最简单的情况...阅读下面的原因)
正如所见,它确实提供了居中的 w/o 帧偏移和正确对齐的边元素,但是......有 缺点 - 它可以在这种最简单的变体中工作仅 如果事先知道那些 三个文本元素在用户 运行 时间内不应重叠。如果是这种情况(真的有这种情况),那么这种方法就可以了。但是,如果 left/right 文本可能会在 运行 时间内增长,那么将需要更多的计算来将它们的宽度限制为 .frame(maxWidth:)
,具体取决于居中元素的宽度...该变体更复杂, 但这是可行的。
var body: some View {
ZStack {
HStack {
Text("Longer side")
Spacer()
Text("One")
}
item2()
}
}
private func item2() -> some View {
Text("CENTER")
.background(Color.yellow)
.border(Color.red)
}
更新: 这是一种可能的方法,可以限制其中一侧不与居中的一侧重叠(包含异步更新,因此应在 实时预览 或模拟器)
所以...如果左侧文本是动态的并且需要剪切尾随符号,那么它可以这样...
它会自动适应设备方向的变化
struct TestHorizontalPinCenter: View {
@State var centerFrame: CGRect = .zero
private let kSpacing: CGFloat = 4.0
var body: some View {
ZStack {
HStack {
Text("Longer side very long text to fit")
.lineLimit(1)
.frame(maxWidth: (centerFrame == .zero ? .infinity : centerFrame.minX - kSpacing), alignment: .leading)
Spacer()
Text("One")
}
item2()
.background(rectReader($centerFrame))
}
}
private func item2() -> some View {
Text("CENTER")
.background(Color.yellow)
.border(Color.red)
}
func rectReader(_ binding: Binding<CGRect>) -> some View {
return GeometryReader { (geometry) -> AnyView in
let rect = geometry.frame(in: .global)
DispatchQueue.main.async {
binding.wrappedValue = rect
}
return AnyView(Rectangle().fill(Color.clear))
}
}
}
而如果需要左侧包裹,则.lineLimit(nil)
需要额外的布局,解决方案增长,但思路是一样的。希望这会对某人有所帮助。
要使视图居中,您可以使用 ZStack:
ZStack {
item2()
HStack {
Text("test")
Spacer()
Text("test")
}
}
我遇到了同样的问题,@Asperi 的解决方案有效,但我遇到了多行文本问题,如果我在列表中使用它,还会出现一些性能问题。
以下解决方案解决了所有问题。
HStack(alignment: .center) {
Text("test")
.frame(maxWidth: .infinity)
item2()
Text("test")
.frame(maxWidth: .infinity)
}