この記事では、TextEditorの実装方法について徹底解説していきたいと思います。
Contents
TextEditorとは?
TextEditorは、2行以上のテキスト表示したり、入力させたりするオブジェクトです。エリア内でスクロールできるため、長文を表示させることが可能です。

このようなオブジェクトのことです。
実装方法は簡単で、@StateのString型の変数を用意して、TextEditor(text: $text)と記載するだけで実装できます。
TextEditorのスタイル
シンプル

struct ContentView: View {
    @State var inputText = ""
    
    var body: some View {
        TextEditor(text: $inputText)
            .padding()
    }
}
枠線をつける

struct ContentView: View {
    @State var inputText = ""
    
    var body: some View {
        TextEditor(text: $inputText)
            .border(.gray, width: 1)
            .padding()
    }
}
.border(.gray, width: 1)で、色と枠線の太さが指定できます。
枠線を丸くする

struct ContentView: View {
    @State var inputText = ""
    
    var body: some View {
        TextEditor(text: $inputText)
            .overlay(RoundedRectangle(cornerRadius: 5).stroke(.gray, lineWidth: 1))
            .padding()
    }
}
枠線を丸くする場合は、.overlay(RoundedRectangleを使って実装します。
cornerRadius: 5で、枠線の丸みが変えられます。
.stroke(.gray, lineWidth: 1))で、色と枠線の太さが変えられます。
幅と高さを変える

struct ContentView: View {
    @State var inputText = ""
    
    var body: some View {
        TextEditor(text: $inputText)
            .border(.gray, width: 1)
            .frame(width: 150, height: 150)
            .padding()
    }
}
※わかりやすいように枠線をつけてます。
.frame(width: 150, height: 150)で高さと幅を指定できます。
文字の大きさと色を変更

struct ContentView: View {
    @State var inputText = ""
    
    var body: some View {
        TextEditor(text: $inputText)
            .font(.largeTitle)
            .foregroundColor(.red)
            .padding()
    }
}
Textと同様.fontで大きさとフォントを変更できます。
.foregroundColorで文字色が変更できます。
テキストの位置を変える

struct ContentView: View {
    @State var inputText = ""
    
    var body: some View {
        TextEditor(text: $inputText)
            .multilineTextAlignment(.center)
            .border(.gray)
            .padding()
    }
}
※わかりやすいように枠線をつけてます。
テキストの行間を変える

struct ContentView: View {
    @State var inputText = ""
    
    var body: some View {
        TextEditor(text: $inputText)
            .lineSpacing(30)
            .border(.gray)
            .padding()
    }
}
※わかりやすいように枠線をつけてます。
影をつける

struct ContentView: View {
    @State var inputText = ""
    
    var body: some View {
        TextEditor(text: $inputText)
            .border(.gray)
            .shadow(color: .gray, radius: 10, x: 10, y: 10)
            .padding()
    }
}
※わかりやすいように枠線をつけてます。
背景色を変更する

struct ContentView: View {
    @State var inputText = ""
    var body: some View {
        TextEditor(text: $inputText)
            .border(.gray)
            .background(.green)
            .padding()
            .onAppear() {
                UITextView.appearance().backgroundColor = .clear
            }
            .onDisappear() {
                UITextView.appearance().backgroundColor = nil
            }
    }
}
.background(.green)をつけるだけで良いように思えますが、UITextViewの背景色で上書き?されるので、それだけでは背景色を変更できません。
そのため、一旦UITextViewの背景色を透明にしてから、.background(.green)を設定する必要があります。
ということで、以下の3行で、UITextViewの背景色を透明にします。
.onAppear() {
    UITextView.appearance().backgroundColor = .clear
}
その後で、.background(.green)が呼ばれるので緑色になるということです。
で、念の為、透明にした背景色をnilに戻しておきます。
.onDisappear() {
    UITextView.appearance().backgroundColor = nil
}
TextFieldの制御
アルファベットの自動大文字変換をオフにする

struct ContentView: View {
    @State var inputText = ""
    
    var body: some View {
        TextEditor(text: $inputText)
            .autocapitalization(.none)
            .border(.gray)
            .padding()
    }
}
※わかりやすいように枠線をつけてます。
自動的に、最初の単語は大文字に変換されてしまいます。それをこちらのコードで無効にすることができます。
単語の自動修正をオフにする

struct ContentView: View {
    @State var inputText = ""
    
    var body: some View {
        TextEditor(text: $inputText)
            .disableAutocorrection(true)
            .border(.gray)
            .padding()
    }
}
※わかりやすいように枠線をつけてます。
間違えた単語を打つと、確定した時に自動で単語に変換されますが、.disableAutocorrection(true)にすると、変換されなくなります。
案外、自分の名前とかを打つとき、自動変換が邪魔になる時があるので、結構この指定は使うかもしれません。
キーボードタイプ

struct ContentView: View {
    @State var inputText = ""
    
    var body: some View {
        TextEditor(text: $inputText)
            .keyboardType(.emailAddress)
            .border(.gray)
            .padding()
    }
}
※わかりやすいように枠線をつけてます。
.keyboardType(.emailAddress)でキーボードのタイプを指定できます。12種類あります。
| タイプ | 説明 | 
|---|---|
| .default | デフォルト(指定なしだとこれになる) | 
| .asciiCapable | ASCII | 
| .numbersAndPunctuation | 数字と句読点 | 
| .URL | URL | 
| .numberPad | PIN入力用のテンキー | 
| .phonePad | 電話番号 | 
| .namePhonePad | 人の名前や電話番号を入力するためのキーパッド | 
| .emailAddress | メールアドレス | 
| .decimalPad | 数字と小数点 | 
| .twitter | Twitterのテキスト入力用 | 
| .webSearch | Web検索用語やURL入力用 | 
| .asciiCapableNumberPad | ASCIIの数字のみを出力するナンバーパッド | 
ただ、キーボードのタイプを変えたからと言って、そのキーボードにあるキーしか打たれないということはありません。なぜなら、コピペができるからです。
書き込めなくする
ただ単に表示したいだけというときは、以下のように.disabled(true)をつけると編集できなくなります。falseで書き込めるようになります。
struct ContentView: View {
    @State var inputText = ""
    
    var body: some View {
        TextEditor(text: $inputText)
            .frame(height: 180)
            .border(.gray)
            .disabled(true)
            .padding()
    }
}
イベントを取得
タップされたとき
以下のコードでTextFieldをタップした時のイベントが取得できます。
struct ContentView: View {
    @State var inputText = ""
    
    var body: some View {
        TextEditor(text: $inputText)
            .onTapGesture() {
                print("タップされたよ")
            }
    }
}
値が変わったとき
入力されるたびに、.onChangeが呼ばれます。
struct ContentView: View {
    @State var inputText = ""
    
    var body: some View {
        TextEditor(text: $inputText)
            .onChange(of: inputText) { newValue in
                print("入力された値:\(newValue)")
            }
    }
}
プレースホルダーを自作する
TextFieldにはあって、TextEditorにないもの。それはプレースホルダーです。
プレースホルダーというのは、TextEditorやTextFieldで何も文字が入力されていないときに、入力する内容のヒントを書くためのものです。以下の画像のようにグレーで薄く文字が表示されます。文字を入力すると消えます。
このプレースホルダーですが、TextFieldはプレースホルダーを設定できるのですが、TextEditorは設定できません。そのため自作しなければなりません。

struct ContentView: View {
    @State private var inputText = ""
    
    var body: some View {
        ZStack(alignment: .topLeading) {
            TextEditor(text: $inputText)
                .border(.gray)
                .frame(height: 180)
                .padding()
            if inputText.isEmpty {
                Text("ここに文字を入力してください。")
                    .foregroundColor(Color(uiColor: .placeholderText))
                    .allowsHitTesting(false)
                    .padding(20)
                    .padding(.top, 5)
            }
        }
    }
}
実装方法は単純で、TextEditor内の文字が入力されていない場合、TextEditorの上にグレーの文字を配置するという内容です。
まず、重ねるのでZStackを使い、左上に揃えます。
ZStack(alignment: .topLeading) {
もし、inputTextが空文字の場合は、Textを表示します。
if inputText.isEmpty {
    Text("ここに文字を入力してください。")
Textを重ねているので、プレースホルダー部分のTextをタップすると、TextEditorがタップされなくなりカーソルが合わなくなります。
そのため、以下の指定をしてTextを触ってもTextEditorが反応するようにします。
.allowsHitTesting(false)
あとは、.paddingでちょうど良い場所に調整するだけです。
.padding(20) .padding(.top, 5)
TextEditorのプレースホルダーに関する記事は色々とあるので、自分に合ったプレースホルダーの実装をしてみてください。
参考 【SwiftUI】TextEditorにプレースホルダーを表示するQiita 参考 SwiftUI TextEditor にプレースホルダーを設定するGitHub 参考 SwiftUIのTextEditorでもプレースホルダーを使いたいLento con forza参考文献


