Lento con forza

大学生気分のIT系エンジニアが色々書いてく何か。ブログ名決めました。

SwiftUIのTextEditorでもプレースホルダーを使いたい

---WWDCアップデート---
WWDC22でのアップデートで、iOS 16以降は標準のTextFieldでこれを実現できるようになりました!こちらも合わせてご確認ください!こちらの記事はiOS 15以下向けのものとして、参考にしてください。

kouki.hatenadiary.com


SwiftUIで複数行を入力したいときに使うTextEditorですが、TextFieldのように、その入力欄が何を表すのかを指定することができません。

iOSアプリではそのようなパターンにはプレースホルダーがよく使われます。なので、SwiftUIのTextEditorにプレースホルダーのUIを追加する実装をしてみました。

ZStackで上にプレースホルダーのテキストを重ねる形で実装してみました。

struct ContentView: View {
    @State private var text = ""
    var body: some View {
        Form {
            ZStack(alignment: .topLeading) {
                TextEditor(text: $text)
                    .padding(.horizontal, -4)
                    .frame(minHeight: 200)
                if text.isEmpty {
                    Text("Placeholder") .foregroundColor(Color(uiColor: .placeholderText))
                        .padding(.vertical, 8)
                        .allowsHitTesting(false)
                }
            }
        }
    }
}

TextEditorにはデフォルトのpaddingが入っているのですが、その値をどうしても取得できなかったのでハードコーディングしています。horizontalをTextEditor、verticalをプレースホルダーのテキストに指定しているのは、できるだけデフォルトのpaddingを尊重した上で、TextFieldと並べた時の見た目を揃えるためです。

プレースホルダーのテキストの上をタップしても入力開始したいので、.allowsHItTesting(false)も指定しています。

というわけで、無理やり解決した感が拭えないですが、このように実装してみました。

もっと良いやり方があれば教えてください!