List のデフォルト表示では物足りない場合、カスタム行を作成して独自のデザインを実現できます。再利用可能なコンポーネントとして切り出す方法も含めて解説します。
基本的なカスタム行
List の各行には任意の SwiftUI ビューを配置できます。HStack を使って横並びのレイアウトを作るのが基本パターンです。
struct ContentView: View { var body: some View { List { HStack { Image(systemName: "person.circle.fill") .font(.title) .foregroundColor(.blue) VStack(alignment: .leading) { Text("山田太郎") .font(.headline) Text("yamada@example.com") .font(.subheadline) .foregroundColor(.gray) } Spacer() Image(systemName: "chevron.right") .foregroundColor(.gray) } } } }
再利用可能な行コンポーネント
同じデザインの行を複数箇所で使う場合は、別のビューとして切り出します。
struct UserRow: View { let user: User var body: some View { HStack { Image(systemName: "person.circle.fill") .font(.title) .foregroundColor(.blue) VStack(alignment: .leading) { Text(user.name) .font(.headline) Text(user.email) .font(.subheadline) .foregroundColor(.gray) } } } } struct User: Identifiable { let id = UUID() var name: String var email: String } struct ContentView: View { let users = [ User(name: "山田太郎", email: "yamada@example.com"), User(name: "佐藤花子", email: "sato@example.com") ] var body: some View { List(users) { user in UserRow(user: user) } } }
複雑なレイアウトの行
画像、タイトル、サブタイトル、バッジなどを含む複雑な行も自由に作成できます。
struct ProductRow: View { let product: Product var body: some View { HStack(spacing: 12) { // 商品画像 RoundedRectangle(cornerRadius: 8) .fill(Color.gray.opacity(0.3)) .frame(width: 60, height: 60) .overlay { Image(systemName: "photo") .foregroundColor(.gray) } // 商品情報 VStack(alignment: .leading, spacing: 4) { Text(product.name) .font(.headline) Text(product.category) .font(.caption) .foregroundColor(.secondary) HStack { Text("¥\(product.price)") .font(.subheadline) .fontWeight(.bold) .foregroundColor(.blue) if product.isOnSale { Text("SALE") .font(.caption2) .fontWeight(.bold) .foregroundColor(.white) .padding(.horizontal, 6) .padding(.vertical, 2) .background(Color.red) .cornerRadius(4) } } } Spacer() } .padding(.vertical, 4) } }
行のパディング調整
List は自動的に行にパディングを追加します。これを調整したい場合は listRowInsets モディファイアを使います。
List { HStack { Color.blue Text("端から端まで") } .listRowInsets(EdgeInsets()) // パディングをゼロに }
listRowInsets
行の内側の余白を調整する。EdgeInsets() を渡すとパディングがゼロになる。
listRowBackground
行の背景色やビューをカスタマイズする。
listRowSeparator
区切り線の表示・非表示を制御する。
条件付きスタイリング
データの状態に応じて行の見た目を変えることもできます。
struct TaskRow: View { let task: Task var body: some View { HStack { Image(systemName: task.isCompleted ? "checkmark.circle.fill" : "circle") .foregroundColor(task.isCompleted ? .green : .gray) Text(task.title) .strikethrough(task.isCompleted) .foregroundColor(task.isCompleted ? .gray : .primary) } } }
カスタム行を作成する際は、再利用性を意識してビューを分割し、データモデルと表示ロジックを明確に分離することがポイントです。