如何在 SwiftUI 中向 TextEditor 添加占位符文本?

Leg*_*ang 21 user-interface uikit ios swift swiftui

使用 SwiftUI 的新 TextEditor 时,您可以直接使用 @State 修改其内容。但是,我还没有看到向其中添加占位符文本的方法。现在可行吗?

在此处输入图片说明

我添加了一个 Apple 在他们自己的翻译应用程序中使用的示例。这似乎是一个支持占位符文本的多行文本编辑器视图。

Mag*_*nus 36

您可以使用禁用的 ZStack,其中TextEditor包含后面的占位符文本。例如:

ZStack {
    if self.content.isEmpty {
            TextEditor(text:$placeholderText)
                .font(.body)
                .foregroundColor(.gray)
                .disabled(true)
                .padding()
    }
    TextEditor(text: $content)
        .font(.body)
        .opacity(self.content.isEmpty ? 0.25 : 1)
        .padding()
}
Run Code Online (Sandbox Code Playgroud)

  • 截至 2023 年 4 月,仍然没有可用的占位符 API。因此,此解决方法仍然是解决此问题的最简单的解决方案。 (3认同)

bde*_*dev 24

开箱即用是不可能的,但您可以使用ZStack.overlay属性实现此效果。

您应该做的是检查持有您所在州的财产。如果为空,则显示您的占位符文本。如果不是,则显示输入的文本。

这是一个代码示例:

ZStack(alignment: .leading) {
    if email.isEmpty {
        Text(Translation.email)
            .font(.custom("Helvetica", size: 24))
            .padding(.all)
    }
    
    TextEditor(text: $email)
        .font(.custom("Helvetica", size: 24))
        .padding(.all)
}
Run Code Online (Sandbox Code Playgroud)

注意:我特意留下了 .font 和 .padding 样式让你看到它应该在 TextEditor 和 Text 上都匹配。

编辑:考虑到 Legolas Wang 在此处的评论中提到的两个问题是如何处理对齐和不透明度问题:

  • 为了使文本从视图的左侧开始,只需将其包装在 HStack 中并在其后立即附加 Spacer,如下所示:
HStack {
   Text("Some placeholder text")
   Spacer()
}
Run Code Online (Sandbox Code Playgroud)
  • 为了解决不透明问题,您可以使用条件不透明度 - 最简单的方法是使用三元运算符,如下所示:
TextEditor(text: stringProperty)        
        .opacity(stringProperty.isEmpty ? 0.25 : 1)
Run Code Online (Sandbox Code Playgroud)

当然,在为 TextEditor 添加支持之前,此解决方案只是一种愚蠢的解决方法。

  • 对于占位符文本颜色,您可以使用: .foregroundColor(Color(UIColor.placeholderText)) (3认同)

cs4*_*der 18

我修改了 @bde.dev 解决方案,这里是代码示例和屏幕截图。

   struct TextEditorWithPlaceholder: View {
        @Binding var text: String
        
        var body: some View {
            ZStack(alignment: .leading) {
                if text.isEmpty {
                   VStack {
                        Text("Write something...")
                            .padding(.top, 10)
                            .padding(.leading, 6)
                            .opacity(0.6)
                        Spacer()
                    }
                }
                
                VStack {
                    TextEditor(text: $text)
                        .frame(minHeight: 150, maxHeight: 300)
                        .opacity(text.isEmpty ? 0.85 : 1)
                    Spacer()
                }
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

我认为它是这样使用的:

   struct UplodePostView: View {
        @State private var text: String = ""
        
        var body: some View {
            NavigationView {
                Form {
                    Section {
                        TextEditorWithPlaceholder(text: $text)
                    }
                }
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

输出

  • 应该在顶部 (2认同)

maw*_*wus 9

在我们有一些 API 支持之前,一个选项是使用绑定字符串作为占位符并使用 onTapGesture 将其删除

TextEditor(text: self.$note)
                .padding(.top, 20)
                .foregroundColor(self.note == placeholderString ? .gray : .primary)
                .onTapGesture {
                    if self.note == placeholderString {
                        self.note = ""
                    }
                }
Run Code Online (Sandbox Code Playgroud)

  • 如果用户输入占位符字符串怎么办? (2认同)
  • 请不要这样做,这会带来各种各样的问题。 (2认同)

Ima*_*tit 8

使用TextFieldinit(_:text:axis:)初始化程序

在 iOS 16 中,作为 的替代方案TextEditor,您可以TextField使用init(_:text:axis:)初始值设定项创建多行。

以下代码显示了TextField带有本机占位符的多行:

import SwiftUI

struct ContentView: View {
    @State private var note = ""
    @FocusState private var isFocused: Bool

    var body: some View {
        Form {
            TextField("Note", text: $note, axis: .vertical)
                .lineLimit(2...)
                .focused($isFocused)
        }
        .toolbar {
            ToolbarItemGroup(placement: .keyboard) {
                Spacer()
                Button("Done") {
                    isFocused = false
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

TextEditor与自定义占位符一起使用

如果您需要使用 aTextEditor而不是 multiline TextField,您可以为其创建自定义占位符。从 iOS 15 开始,FocusState可以帮助管理 a 的焦点状态TextEditor(例如显示或隐藏其自定义占位符)。

以下代码显示了TextEditor带有自定义占位符的 a 的可能实现:

import SwiftUI

struct ContentView: View {
    @State private var note = ""
    @FocusState private var isFocused: Bool

    var body: some View {
        Form {
            ZStack(alignment: .topLeading) {
                TextEditor(text: $note)
                    .focused($isFocused)
                if !isFocused && note.isEmpty {
                    Text("Note")
                        .foregroundColor(Color(uiColor: .placeholderText))
                        .padding(.top, 10)
                        .allowsHitTesting(false)
                }
            }
        }
        .toolbar {
            ToolbarItemGroup(placement: .keyboard) {
                Spacer()
                Button("Done") {
                    isFocused = false
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我相信这是 2022 年所有解决方案中最优越、最新的版本!FocusState +1 和使用 .allowsHitTesting(false) +1 (4认同)

gre*_*rey 6

我构建了一个可以像这样使用的自定义视图(直到 TextEditor 正式支持它 - 也许明年)

TextArea("This is my placeholder", text: $text)
Run Code Online (Sandbox Code Playgroud)

完整解决方案如下:

struct TextArea: View {
    private let placeholder: String
    @Binding var text: String
    
    init(_ placeholder: String, text: Binding<String>) {
        self.placeholder = placeholder
        self._text = text
    }
    
    var body: some View {
        TextEditor(text: $text)
            .background(
                HStack(alignment: .top) {
                    text.isBlank ? Text(placeholder) : Text("")
                    Spacer()
                }
                .foregroundColor(Color.primary.opacity(0.25))
                .padding(EdgeInsets(top: 0, leading: 4, bottom: 7, trailing: 0))
            )
    }
}

extension String {
    var isBlank: Bool {
        return allSatisfy({ $0.isWhitespace })
    }
}
Run Code Online (Sandbox Code Playgroud)

我在这里使用TextEditor的默认填充,但您可以根据自己的喜好随意调整。


fl0*_*034 5

iOS 16 的原生解决方案

而不是TextEditor使用TextField. 自 iOS 16 起,当使用带有参数的初始化程序之一时,它本身支持多行,当然还有占位符axis

TextField("Placeholder...", text: .constant("hey"), axis: .vertical)
    .lineLimit(1...5)
Run Code Online (Sandbox Code Playgroud)

通过范围,您甚至可以说出最小TextField可以达到多大。或者使用linelimit(_:reservesSpace:)

您可能会错过 TextEditor 的一些功能,但对我来说它运行得很好。