代码之家  ›  专栏  ›  技术社区  ›  Lorenzo Zorri

如何根据文本字段的内容动态调整其宽度?

  •  0
  • Lorenzo Zorri  · 技术社区  · 6 月前

    我想在SwiftUI中创建一个TextField,根据内容动态调整其宽度,而不添加额外的间距。

    TextField是具有多个文本视图的HStack的一部分,我的目标是让它作为文本的一部分无缝显示。例如,结果应该看起来像这样:

    Text("Text(") + Text("\"") + TextField + Text("\"") + Text(")")
    

    我尝试使用.fixedSize()修饰符,当文本变长时,它可以很好地工作。但是,当文本变短时,它不会缩小宽度,TextField会保留初始大小。

    以下是我尝试过的一个简化示例:

    import SwiftUI
    
    struct ContentView: View {
        @State private var text: String = ""
    
        var body: some View {
            HStack(spacing: 0) {
                Text("Text(")
                Text("\"")
                TextField("Placeholder", text: $text)
                    .fixedSize()
                    .textFieldStyle(PlainTextFieldStyle())
                Text("\"")
                Text(")")
            }
            .font(.system(size: 15, weight: .medium, design: .monospaced))
        }
    }
    

    TextField适用于较长的文本,但当内容比初始文本短时,它不会动态收缩。

    有没有一种方法可以让TextField表现得像文本视图一样,在不留额外间距的情况下动态调整其宽度?还是手动宽度计算是唯一的选择?

    任何帮助都将不胜感激!

    2 回复  |  直到 6 月前
        1
  •  1
  •   Benzy Neez    6 月前

    您可以在背景中显示相同的文本,并使用以下方法测量其宽度 .onGeometryChange 。然后将此宽度作为固定宽度应用于 TextField .

    • 虽然从其名称中不明显, .on几何变化 还报告了初始大小。
    • 申请 .fixedSize() 以允许它超出其帧的边界。
    • 也适用 .hidden() ,以防止被人看到。
    @State private var textWidth = CGFloat.zero
    
    TextField("Placeholder", text: $text)
        .frame(width: textWidth)
        .textFieldStyle(PlainTextFieldStyle())
        .background {
            Text(text.isEmpty ? "Placeholder" : text)
                .fixedSize()
                .hidden()
                .onGeometryChange(for: CGFloat.self) { proxy in
                    proxy.size.width
                } action: { newVal in
                    textWidth = newVal
                }
        }
    

    Animation

    您可能希望将尺寸读取部分包装为 ViewModifier ,使其更可重复使用。答案是 How to get size of child? 展示了如何做到这一点(这是我的答案)。

        2
  •  0
  •   CouchDeveloper    6 月前

    你可以尝试一下 fixedSize 修改器:

    HStack {
        TextField("Prefix", text: $prefix)
            .fixedSize()
        TextField("Text", text: $text)
            .fixedSize()
        TextField("Suffix", text: $suffix)
            .fixedSize()
    }
    

    可能与限制最小宽度相结合:

    HStack {
        TextField("Prefix", text: $prefix)
            .frame(minWidth: 10, maxWidth: 300)
            .fixedSize()
        TextField("Text", text: $text)
            .fixedSize()
        TextField("Suffix", text: $suffix)
            .fixedSize()
    }
    

    请注意,TextField的宽度不会缩小到小于其提示/占位符的宽度。

    更新:

    这个简单的解决方案并不总是能正常工作:当输入文本后,选择该文本,然后删除,文本字段将不会再次收缩。不过,删除单个字符时,它似乎有效。因此,我们需要进一步调查这一点。