作成するもの
連絡帳アプリにある特定のアルファベットの連絡先に直接ジャンプできる機能を実装していきます。
これを実現するためにUITableViewDelegateプロトコルのメソッドで適宜されているsectionIndexTitles
を用いてテーブルビューの右側に表示されるセクションインデックスのタイトルを作成します。
完成アプリ
実装
今回作成したTableViewControllerを記述しています。
ContentView.swift
struct ContentView: View {
var body: some View {
VStack {
TableViewController { item in
print(item)
}
}
}
}
国データを定義しています。
DataSources.swift
import Foundation
struct DataSources {
static let data = [
Section(
title: "A",
items: [
Item(name: "Afghanistan"),
Item(name: "Albania")
]
),
Section(
title: "B",
items: [
Item(name: "Bahamas"),
Item(name: "Belgium")
]
),
Section(
title: "C",
items: [
Item(name: "China"),
Item(name: "Czechia"),
]
),
Section(
title: "D",
items: [
Item(name: "Denmark")
]
),
Section(
title: "E",
items: [
Item(name: "Egypt"),
Item(name: "Ethiopia")
]
),
Section(
title: "F",
items: [
Item(name: "France")
]
),
Section(
title: "G",
items: [
Item(name: "Germany"),
Item(name: "Greece"),
Item(name: "Guinea"),
]
),
Section(
title: "H",
items: [
Item(name: "Hungary")
]
),
Section(
title: "I",
items: [
Item(name: "India"),
Item(name: "Indonesia")
]
),
Section(
title: "J",
items: [
Item(name: "Japan"),
Item(name: "Jordan")
]
),
Section(
title: "K",
items: [
Item(name: "Korea")
]
),
Section(
title: "L",
items: [
Item(name: "Latvia")
]
),
Section(
title: "M",
items: [
Item(name: "Malaysia")
]
),
Section(
title: "N",
items: [
Item(name: "Nepal")
]
),
Section(
title: "O",
items: [
Item(name: "Oman")
]
),
Section(
title: "P",
items: [
Item(name: "Peru")
]
),
Section(
title: "R",
items: [
Item(name: "Russian")
]
),
Section(
title: "S",
items: [
Item(name: "Spain")
]
),
Section(
title: "T",
items: [
Item(name: "Thailand")
]
)
]
struct Section {
let title: String
let items: [Item]
}
struct Item {
let name: String
}
}
UIViewControllerRepresentable プロトコルを使用して、SwiftUIビュー内でUIKitのUITableViewControllerを使用できるようにしています。sectionIndexColor
は、UITableViewDelegateプロトコルのメソッドで、テーブルビューの右側に表示されるセクションインデックスのタイトルを提供します。またsectionIndexColor
でセクションインデックスのタイトルの色を変更できます。
TableViewController.swift
import Foundation
import SwiftUI
struct TableViewController: UIViewControllerRepresentable {
private var sections = DataSources.data
var onSelect: ((DataSources.Item) -> Void)?
init(onSelect: ((DataSources.Item) -> Void)? = nil) {
self.onSelect = onSelect
}
func makeUIViewController(context: UIViewControllerRepresentableContext<TableViewController>) -> UITableViewController {
let tableViewController = UITableViewController(style: .insetGrouped)
//この行のコードでは、データソースをCoordinatorオブジェクトに設定しています。CoordinatorオブジェクトはUITableViewDataSourceプロトコルに準拠しており、テーブルビューのデータを提供します。
tableViewController.tableView.dataSource = context.coordinator
//この行のコードでは、デリゲートをCoordinatorオブジェクトに設定しています。CoordinatorオブジェクトはUITableViewDelegateプロトコルに準拠しており、テーブルビューの見た目や動作を制御します。
tableViewController.tableView.delegate = context.coordinator
tableViewController.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
// change sectionIndex color
tableViewController.tableView.sectionIndexColor = .lightGray
return tableViewController
}
func updateUIViewController(_ uiViewController: UITableViewController, context: UIViewControllerRepresentableContext<TableViewController>) {
// Update your controller here.
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UITableViewDataSource, UITableViewDelegate {
var parent: TableViewController
init(_ parent: TableViewController) {
self.parent = parent
}
func numberOfSections(in tableView: UITableView) -> Int {
return parent.sections.count
}
// これだけでSectionIndexが実装できる
func sectionIndexTitles(for tableView: UITableView) -> [String]? {
return parent.sections.map { $0.title }
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return parent.sections[section].title
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return parent.sections[section].items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = parent.sections[indexPath.section].items[indexPath.row].name
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
parent.onSelect?(parent.sections[indexPath.section].items[indexPath.row])
tableView.deselectRow(at: indexPath as IndexPath, animated: true)
}
}
}