水平堆栈内的中心项目 [英] Center Item Inside Horizontal Stack

查看:29
本文介绍了水平堆栈内的中心项目的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我在 Horizo​​ntal Stack 中有 3 个项目,我想我可以这样做:

If I have 3 items inside a Horizontal Stack, I thought I could do something like this:

HStack{

      Text("test")

      Spacer()

      item2()

      Spacer()

      Text("test")
}

将 item2() 置于两个 Text 视图之间.但是,问题在于 item2() 不一定总是居中,因为可以说 Text("test") 更改为 Text("a") 或其他内容.这会导致问题,并且第二项并不总是位于屏幕中央.

to center item2() in between the two Text views. However, the problem with this is that item2() isn't necessarily always centered, because, lets say Text("test") changes to Text("a") or something. This causes problems, and the second item isn't always centered on the screen.

我怎样才能让 item2() 始终居中?

How can I make it so item2() is always centered?

谢谢

推荐答案

我会提出以下起点(最简单的情况...阅读下面的原因)

I would propose the following start point (simplest case... read below why)

正如它所看到的,它确实提供了居中的无帧偏移和正确对齐的侧边元素,但是......有缺点 - 它可以在这种最简单的变体中工作> 如果事先知道这三个文本元素在用户运行时不应重叠.如果是这种情况(确实有这种情况),那么这种方法就行了.但是,如果左/右文本可能在运行时增长,则需要更多的计算来通过 .frame(maxWidth:) 限制它们的宽度,具体取决于居中元素的宽度......该变体是比较复杂,但可行.

As it's seen it really gives centred w/o frame shift with correctly aligned side elements, but ... there is drawback - it will work in such simplest variant only if it is known in advance that those three text elements should never overlap in user run-time. If it is the case (really there are such) then this approach just goes. However if left/right text might grow in run-time, then more calculations will be needed to limit their width by .frame(maxWidth:) depending on the width of centred element... that variant is more complicated, but it is feasible.

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)
}

更新:这里有一种可能的方法来限制一侧不重叠居中的一侧(包含异步更新,因此应在实时预览或模拟器中进行测试)

Update: here is possible approach to limit one of the side to not overlap centred one (contains async updates, so should be tested in Live Preview or Simulator)

所以...如果左边的文本是动态的并且需要剪切尾随符号,那么它是如何进行的...

So... if left text is dynamic and the requirement to cut trailing symbols, here is how it could go ...

它会自动适应设备方向的变化

and it automatically fit well on device orientation change

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) 和额外的布局,以及解决方案的增长,但思路是一样的.希望这对某人有帮助.

And if it is needed to wrap left side, then .lineLimit(nil) and additional layout will be needed, and solution growth, but the idea is the same. Hope this will be helpful for someone.

这篇关于水平堆栈内的中心项目的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆