【SwiftUI】TextEditorの使い方を徹底解説~背景色変更、枠線、タップ判定、自動変換~

この記事では、TextEditorの実装方法について徹底解説していきたいと思います。

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にないもの。それはプレースホルダーです。

プレースホルダーというのは、TextEditorTextFieldで何も文字が入力されていないときに、入力する内容のヒントを書くためのものです。以下の画像のようにグレーで薄く文字が表示されます。文字を入力すると消えます。

このプレースホルダーですが、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