You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中如何让TextField根据内容动态调整宽度?

解决SwiftUI TextField动态收缩宽度的问题

你遇到的核心问题是:TextField使用.fixedSize()后仅能随内容扩展宽度,却无法在内容缩短时自动收缩。这是因为.fixedSize()会让视图保留其渲染过的最大尺寸,不会主动缩小。下面提供两种可行的解决方案:

方法一:通过PreferenceKey实时计算文本宽度

自定义PreferenceKey来获取文本的实际宽度,再将该宽度绑定给TextField,实现宽度的实时动态调整:

import SwiftUI

struct TextWidthPreferenceKey: PreferenceKey {
    static var defaultValue: CGFloat = 0
    static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
        value = nextValue()
    }
}

struct ContentView: View {
    @State private var text: String = ""
    @State private var textWidth: CGFloat = 0
    
    var body: some View {
        HStack(spacing: 0) {
            Text("Text(")
            Text("\"")
            
            TextField("Placeholder", text: $text)
                .textFieldStyle(PlainTextFieldStyle())
                .frame(width: textWidth)
                .background(
                    // 用隐藏的Text同步内容,获取真实宽度
                    Text(text.isEmpty ? "Placeholder" : text)
                        .font(.system(size: 15, weight: .medium, design: .monospaced))
                        .hidden()
                        .overlay(
                            GeometryReader { proxy in
                                Color.clear.preference(key: TextWidthPreferenceKey.self, value: proxy.size.width)
                            }
                        )
                )
            
            Text("\"")
            Text(")")
        }
        .font(.system(size: 15, weight: .medium, design: .monospaced))
        .onPreferenceChange(TextWidthPreferenceKey.self) { newValue in
            textWidth = newValue
        }
    }
}

原理说明

  • 用隐藏的Text同步显示TextField的内容(或占位符),通过GeometryReader捕获它的实际宽度
  • 借助PreferenceKey将宽度值传递给父视图,再把该值设置为TextField的宽度
  • 确保TextField的宽度完全跟随文本内容变化,无论是扩展还是收缩都能实时响应

方法二:ZStack结合隐藏Text同步尺寸

这种方式更简洁,通过ZStack让TextField继承隐藏Text的自适应尺寸:

import SwiftUI

struct ContentView: View {
    @State private var text: String = ""
    
    var body: some View {
        HStack(spacing: 0) {
            Text("Text(")
            Text("\"")
            
            ZStack(alignment: .leading) {
                // 隐藏的Text自动适配内容宽度,作为容器尺寸参考
                Text(text.isEmpty ? "Placeholder" : text)
                    .font(.system(size: 15, weight: .medium, design: .monospaced))
                    .hidden()
                
                TextField("", text: $text)
                    .textFieldStyle(PlainTextFieldStyle())
                    .font(.system(size: 15, weight: .medium, design: .monospaced))
                    .offset(x: 1) // 微调光标对齐,可根据字体调整
            }
            
            Text("\"")
            Text(")")
        }
        .font(.system(size: 15, weight: .medium, design: .monospaced))
    }
}

原理说明

  • 隐藏的Text会根据内容自动伸缩宽度,ZStack会以这个Text的尺寸作为容器大小
  • TextField放在ZStack中,会自动适配容器尺寸,从而实现随内容收缩、扩展的效果

注意事项

  • 必须保证TextField和同步用的Text使用完全一致的字体设置,否则宽度计算会出现偏差
  • 上述方案针对单行文本嵌入场景设计,若需支持多行,需额外调整高度适配逻辑

内容的提问来源于stack exchange,提问作者Lorenzo Zorri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 15:22:33