LoginSignup
12
5

【SwiftUI】文字を表示するベストプラクティス(Text・Label / TextEditor・TextField)

Posted at

SwiftUIにはテキストを表示する方法がいくつかあります。
今回はそれぞれの使い分けや使い勝手を考えていきます。

各コンポーネントのできること

  編集  コピー  選択  アイコン
Text × ⚪︎ × ×
Label × ⚪︎ × ⚪︎
TextEditor ⚪︎ ⚪︎ × ×
TextField ⚪︎ ⚪︎ × ×

まず入力があるかないかで大きく分かれます。細かく使い方を見ていきます。

TextEditorとTextFieldの使い分け

TextFieldは改行できないため、改行して入力が必要な場合はTextEditorを使う必要があります。

TextEditor

複数行のスクロール可能なテキストを表示および編集できます。

struct TextEditingView: View {
    @State private var text: String = ""

    var body: some View {
        TextEditor(text: $text)
    }
}

文字の色やフォントなどは、Textでも使用しているforgroundStylefontで設定できます。
1つ注意点はプレースホルダーの機能はないため自分で実装する必要があります。

// allowsHitTesting(false)をつけないとプレースホルダーの部分はタップできなくなるので注意です
struct TextEditingView: View {
    @State private var text: String = ""

    var body: some View {
        TextEditor(text: $text)
            .overlay(alignment: .topLeading) {
                if text.isEmpty {
                    Text("プレースホルダー")
                        .allowsHitTesting(false)
                }
            }
    }
}

ZStackでも問題ないですが、私はこちらの方が好きです。

参考

TextField

1行の文字入力に適しており、UIKitのUITextFieldに近いです。
上記で指摘したプレースホルダーも標準で設定することができ、SecureFieldを使用すればセキュアな入力もできます。

struct TextEditingView: View {
    @State private var username: String = ""

    var body: some View {
        TextField(
            "User name (email address)",
            text: $username
        )
    }
}

複数行に対応する必要がない場合は、TextFieldを使用する方がいいでしょう。

LabelとTextの使い分け

TextとLabelではアイコンが設定できるかどうかが主な差分です。

Label

テキスト+アイコンで構成される標準的なUI。

// 両方表示
Label("Lightning", systemImage: "bolt.fill")

// タイトルだけ
Label("Lightning", systemImage: "bolt.fill")
    .labelStyle(.titleOnly)

// アイコンだけ
Label("Lightning", systemImage: "bolt.fill")
    .labelStyle(.iconOnly)

LabelStyleを定義することで余白などより柔軟なレイアウト変更が可能。

// アイコンとラベルのスペースを横幅いっぱいに広げる
struct Test1LabelStyle: LabelStyle {
    func makeBody(configuration: Configuration) -> some View {
        HStack {
            configuration.icon
                .scaledToFit()
                .frame(width: 24, height: 24)
            Spacer()
            configuration.title
                .font(.title)
                .frame(maxWidth: .infinity, alignment: .trailing)
        }
    }
}

// アイコンとラベルの位置を反転させる
struct Test2LabelStyle: LabelStyle {
    func makeBody(configuration: Configuration) -> some View {
        HStack(spacing: 8) {
            configuration.title
                .font(.title)
                .frame(maxWidth: .infinity, alignment: .leading)
            configuration.icon
                .scaledToFit()
                .frame(width: 24, height: 24)
        }
    }
}

このオプションのところのようなレイアウトも再現できます。

Text

テキストのみを表示する標準的なUI。

Text("Hamlet")

ここまで見てもLabelの有効な活用があまり見えてきません。

Human Interface Guidline

ガイドラインをチェックしてみました。

参考: https://developer.apple.com/design/human-interface-guidelines/labels

Labels - Best practices

Use a label to display a small amount of text that people don’t need to edit. If you need to let people edit a small amount of text, use a text field. If you need to display a large amount of text, and optionally let people edit it, use a text view.

編集する必要のない少量のテキストを表示するには、ラベルを使用します。少量のテキストを編集させる必要がある場合は、テキストフィールドを使用します。大量のテキストを表示し、任意で編集させる必要がある場合は、テキストビューを使用します。

Developer note

To display uneditable text, SwiftUI defines two components: Label and Text.

編集不可能なテキストを表示するために、SwiftUI は2つのコンポーネントを定義します:ラベルとテキストです。

ここで出てくるLabelというのはコンポーネントのことではなく、おそらく⬇︎の総称。

Labelはどういう時に使うのがより有効的なのか考えてみます。

Labelの有効な使い方

私が思いついたLabelの有用な使い道です。

  • サービスのデザインルールとして保存ボタンが星アイコン+保存で表現されている場合

場所によっては文字だけやアイコンだけ表示することもあると思います。
この3パターンある保存ボタンを共通のコンポーネントとして実装するのにLabelは最適です。

残る問題

SwiftUIのコンポーネントには文字列の部分選択をできるコンポーネントは存在しません。
そのため、もし文字列の部分選択を実現したい場合はUIKitで対応するしかありません。意外に不便に思います。

12
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
5