SwiftUIでの文字寄せとか

最近、SwiftUIデビューをした。太古の昔にTitanium MobileでiOSアプリを作ったことはあるが、基本Web畑で育ってきたt32kにとっては、iOSというかSwiftというかSwiftUIでのユーザーインターフェイス作成は、まるで外国での生活のようで、いろいろカルチャーギャップを感じる。そうゆうことを書きたい。

まず初めに、文字寄せだが、テキストを左寄せ・右寄せにしたいときどうすればよいんだろうと思った。Xcodeでプロジェクトを作成するとHello World!の文字列を表示するボイラープレートが用意されている。

この文字列は上下・左右・真ん中に表示されている。これを左寄せにしたい。Webでいう、text-align: leftは、SwiftUIではどうするんだろうと私は考える。

struct ContentView: View {
    var body: some View {
        Text("Hello, World!")
            .frame(alignment: .leading)
    }
}

frameモディファイアでaligmentというプロパティがあるのでそれに.leading2セットすればよいらしい。

なるほど。動かない。

それもそのはずだ、Textビューのサイズ(青枠)を見ればわかる。文字でいっぱいいっぱいなので、どちらか片方に寄せれないっぽい。

struct ContentView: View {
    var body: some View {
        Text("Hello, World!")
            .frame(maxWidth: .infinity, alignment: .leading)
    }
}

Frameのサイズを画面いっぱいにひろげてみると、なるほどな、左に寄せることができた。ちなみに右寄せの場合は.trailingだ。

またStackOveflowでこうゆう回答も見かけた。

struct ContentView: View {
    var body: some View {
        VStack {
            HStack {
                Text("Hello, World!")
                Spacer()
            }
            HStack {
                Spacer()
                Text("Hello, World!")
            }
        }
    }
}

Spacer()使うと楽だぜヒャッハーという。これだとSpacer()が目一杯広がるので、frameのwidthを明示的に指定しなくてもいいし楽っぽい。

でもSpacerというものWebでは邪道と言われ続けたスペーサーGIFのようなものと感じるので、あまり頼りすぎるのではよくないのではないかと思った。alignmentで明示的に文字寄せを表現しているのは意味的に正しいと思う。

てか、そもそもなんで text-align:left/right.leading/.trailing というのか考える必要がある。iOSはアラビア語圏などにも対応している。つまり右から左へ読む文化だ。つまり.leadingと指定した文字寄せは日本語圏などは左になるが、アラビア語圏などでは右に配置されるので、先頭 が変わるからleft/rightという名前なんだと理解した。なるほど、多言語文化対応だ。

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
      ContentView().environment(\.layoutDirection, .rightToLeft)
    }
}

というわけで、環境変数レイアウト方向にRTLにセットしてみると、

struct ContentView: View {
    var body: some View {
        VStack {
            Text("Hello, alignment 左")
                .frame(maxWidth: .infinity, alignment: .leading)
            Text("Hello, alignment 右")
                .frame(maxWidth: .infinity, alignment: .trailing)
            
            HStack {
                Text("Hello, spacer 左")
                Spacer()
            }
            HStack {
                Spacer()
                Text("Hello, spacer 右")
            }
            
            HStack {
                Text("左")
                Spacer()
                Text("右")
            }
        }
    }
}

alignmentで指定した文字寄せは予想通り、反対になっている。予想外だったのはSpacer()で文字寄せしたコードも反対になっている点だ。レイアウト方向にRTLになるとHStack(横方向に並べるやつ)の並びも反転するのか。。。これは頭がよいのか、おせっかいなのかよくわからないけど、注意する必要がある。

まぁ、そんな感じで文字寄せひとつとってもいろいろ発見があるなーと思いました(こなみかん)