フレームワークと戦うのをやめる
SwiftUIコードで頻繁に見かけるパターンが、Buttonのlabelクロージャ内にImageを直接配置してアイコンのみのボタンを手動で作成するものです。見た目は機能しますが、アクセシビリティ情報が失われ、SwiftUIの設計思想に反しています。
間違ったやり方
Button {
toggleSidebar()
} label: {
Image(systemName: "sidebar.left")
}これはタップ可能なアイコンをレンダリングしますが、VoiceOverが読み上げるための意味のあるラベルがありません。ユーザーには「ボタン」や生のSF Symbol名のようなものが聞こえ、役に立ちません。
正しいやり方
Button("Toggle Sidebar", systemImage: "sidebar.left") {
toggleSidebar()
}
.labelStyle(.iconOnly)またはLabelを明示的に使用します:
Button(action: toggleSidebar) {
Label("Toggle Sidebar", systemImage: "sidebar.left")
}
.labelStyle(.iconOnly)![]()
なぜ重要なのか
Labelビューはタイトルとアイコンの両方を保持します。.labelStyle(.iconOnly)を適用すると、SwiftUIは視覚的にはタイトルを非表示にしますが、アクセシビリティツリーには保持します。VoiceOverは「Toggle Sidebar、ボタン」と読み上げます。これはまさにユーザーが聞く必要がある内容です。
このパターンはコードの適応性も向上させます。後でアイコンの横にテキストを表示することにした場合(例えばiPadのツールバーで)、ラベルスタイルを.titleAndIconに変更するだけです。構造の変更は不要です。
ボタン以外への応用
同じ原則はLabelを受け取るすべてのビューに適用されます:NavigationLink、Toggle、Picker、メニューアイテム。単独のImageを使いたくなったときは、スタイルモディファイア付きのLabelの方が適切ではないかを自問してください。ほとんどの場合、そちらの方が適切です。
