LoginSignup
0
0

連絡帳アプリにある特定のアルファベットの連絡先に直接ジャンプできる機能を実装する(sectionIndexTitles)

Last updated at Posted at 2023-07-02

作成するもの

連絡帳アプリにある特定のアルファベットの連絡先に直接ジャンプできる機能を実装していきます。
これを実現するためにUITableViewDelegateプロトコルのメソッドで適宜されているsectionIndexTitlesを用いてテーブルビューの右側に表示されるセクションインデックスのタイトルを作成します。

完成アプリ

RPReplay_Final1688211858.gif

実装

今回作成した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)
        }
    }
}

参考文献

Apple Developer
TableViewのSectionIndexTitlesの位置を調整する

0
0
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
0
0