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

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

问题描述

如果我在水平堆栈中有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( 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)

如所见,它确实提供了中心对齐的无边框偏移和正确对齐的边元素,但是...存在缺点-它可以在这样的最简单的变体 only (如果事先知道在用户运行时这些三个文本元素绝不应该重叠)。如果确实如此(确实有这种情况),那么这种方法就可以了。但是,如果左右文本可能会在运行时增长,则需要进行更多计算才能将其宽度限制为 .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)
}

更新:这是一种可能的方法,可以限制一侧不重叠居中的一侧(包含异步更新,因此应该在 Live Preview 或模拟器中进行测试)

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天全站免登陆