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

SwiftUI中如何实现用户输入时逐行移除对应占位符?

解决SwiftUI TextEditor多行占位符独立显示问题

你的核心问题在于用全局空值判断控制所有占位符,只要TextEditor有内容就全部隐藏。要实现每行占位符独立显示,需要针对每一行的内容单独判断,而非看整个文本是否为空。

修改思路

  1. 将TextEditor的文本按换行符拆分成行数组,分别判断每一行是否为空
  2. 针对每一行的占位符,仅在对应行无内容时显示
  3. 调整占位符布局,让它们和TextEditor的行精准对齐

修改后的完整代码

struct YourView: View {
    @ObservedObject var note: Note // 假设你的Note是ObservableObject类型
    private let textEditorInset = UITextView.appearance().textContainerInset
    
    private var textLines: [String] {
        note.text.components(separatedBy: .newlines)
    }
    
    var body: some View {
        ZStack(alignment: .leading) {
            // 第一行占位符:仅第一行无内容时显示
            if textLines.isEmpty || textLines.first!.isEmpty {
                Text("Recipe Name")
                    .padding(.top, textEditorInset.top)
                    .padding(.leading, textEditorInset.left)
                    .font(.system(size: 20))
                    .foregroundColor(.gray)
            }
            
            // 第二行占位符:未换行到第二行,或第二行无内容时显示
            if textLines.count < 2 || (textLines.count >= 2 && textLines[1].isEmpty) {
                VStack(spacing: 0) {
                    // 占位第一行高度,让第二行占位符对齐TextEditor的第二行
                    Color.clear.frame(height: UIFont.systemFont(ofSize: 20).lineHeight)
                    Text("Recipe made by (link if applicable)")
                        .padding(.leading, textEditorInset.left)
                        .font(.system(size: 20))
                        .foregroundColor(.gray)
                }
                .padding(.top, textEditorInset.top)
            }
            
            TextEditor(text: $note.text)
                .font(.custom("SanFrancisco", fixedSize: 20))
                .onReceive(note.publisher(for: \.text), perform: setName)
                .onReceive(
                    note.publisher(for: \.text)
                        .debounce(for: 0.5, scheduler: RunLoop.main)
                        .removeDuplicates()
                ) { _ in
                    try? PersistenceController.shared.saveContext()
                }
                .navigationTitle(note.name)
        }
    }
    
    private func setName(_ text: String) {
        // 保留你原有setName逻辑
    }
}

关键说明

  • textLines:将文本拆分成行数组,用于单独判断每一行的内容状态
  • 第一行占位符:文本为空或第一行是空字符串时显示
  • 第二行占位符:用户未输入换行(行数不足2),或第二行是空字符串时显示
  • textEditorInset:获取TextEditor默认内边距,让占位符位置更精准,适配不同设备
  • 用字体行高计算第一行占位高度,保证第二行占位符和TextEditor的第二行对齐

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 03:10:38