此用例中的 UILocalizedIndexedCollat​​ion

Tom*_*nik 4 tableview swift

如何添加章节标题索引列表,以UITableView这个用例

@IBOutlet var tableView: UITableView!

var detail: Detail? = nil
var list = [tabledata]()
let search = UISearchController(searchResultsController: nil)

override func viewDidLoad() {

    super.viewDidLoad()
    list = [

        tabledata(name:"something".localized, sort:"sort.something".localized, id:"something.html"),
        tabledata(name:"somethingelse".localized, sort:"sort.somethingelse".localized, id:"somethingelse.html"),
        ...

    ]

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "library", for: indexPath)
    var data: tabledata
    data = list[indexPath.row]
    cell.textLabel!.text = data.name
    return cell

}
Run Code Online (Sandbox Code Playgroud)

现在的重点是表数据将被转换。

注意

  • name: 是实际的单元名称将是 .localized
  • sort:必须帮助á é单元格名称中的字符等进行正确排序(避免它们显示在字母表的末尾)
  • id:调用要显示的 html 文件位置detailViewController(因为名称必须被翻译,我们想要一个静态文本)

节标题和索引列表的通常实现将导致类似

T                 // section header
translation       // cell names
transmission
...

T                 // table in
Übersetzung       // another language
Getriebe
...
Run Code Online (Sandbox Code Playgroud)

UILocalizedIndexedCollat​​ion 的正确模型是什么?


.xcodeproj在我的 github 上。按需提供更多信息。

感谢帮助!

Cod*_*ent 5

编辑:事实证明,在考虑多种语言(尤其是非拉丁语)时,“将每行的第一个字母用作索引”比我想象的要复杂得多。我正在利用UILocalizedIndexedCollation来简化这个任务。


我认为这UILocalizedIndexedCollation比滚动您自己的数据模型更令人困惑。您需要 2 个模型:一个代表行,一个代表节:

// UILocalizedIndexedCollation uses a selector on the `name` property
// so we have to turn this data type in to a class.
class TableRow: NSObject {
    @objc var name: String
    var id: String
    var sectionTitle = ""

    init(name: String, id: String) {
        self.name = name
        self.id = id
    }
}

// TableSection does not have to be a class but we are making it so
// that it's consistent with `TableRow`
class TableSection: NSObject {
    var title: String
    var rows: [TableRow]

    init(title: String, rows: [TableRow]) {
        self.title = title
        self.rows = rows
    }
}
Run Code Online (Sandbox Code Playgroud)

之后,填充和过滤表格非常简单:

class Library: UIViewController, UITableViewDataSource, UITableViewDelegate {

    @IBOutlet var tableView: UITableView!

    var detail: Detail? = nil
    var list = [TableSection]()
    var filter = [TableSection]()
    let search = UISearchController(searchResultsController: nil)
    let collation = UILocalizedIndexedCollation.current()

    override func viewDidLoad() {

        super.viewDidLoad()

        // search
        search.searchResultsUpdater = self as UISearchResultsUpdating
        search.obscuresBackgroundDuringPresentation = false
        search.searchBar.placeholder = "search".localized
        navigationItem.hidesSearchBarWhenScrolling = false
        navigationItem.searchController = search
        definesPresentationContext = true

        // Set the color of the index on the right of the table.
        // It's settable from Interface Builder as well
        tableView.sectionIndexColor = UIColor(red: 0, green: 122.0 / 255.0, blue: 1, alpha: 1)

        // I took the liberty to add a few more items to the array
        let rows = ["something", "somethingelse", "apple", "orange", "apricot", "strawberry"].map {
            TableRow(name: $0.localized, id: $0)
        }
        list = organizeIntoSections(rows: rows)
        tableView.reloadData()
    }

    // Organize rows into sections with titles
    func organizeIntoSections(rows: [TableRow]) -> [TableSection] {
        // Organize the rows into sections based on their `name` property
        let selector: Selector = #selector(getter: TableRow.name)

        // Sort the rows by `name`
        let sortedRows = collation.sortedArray(from: rows, collationStringSelector: selector) as! [TableRow]

        // Allocate rows into sections
        var sections = collation.sectionTitles.map { TableSection(title: $0, rows: []) }
        for row in sortedRows {
            let sectionNumber = collation.section(for: row, collationStringSelector: selector)
            sections[sectionNumber].rows.append(row)
        }

        // Remove empty sections
        sections.removeAll(where: { $0.rows.isEmpty })
        return sections
    }


    override func viewWillAppear(_ animated: Bool) {
        if let selection = tableView.indexPathForSelectedRow {
            tableView.deselectRow(at: selection, animated: animated)
        }
        super.viewWillAppear(animated)
    }

    // MARK: - Table View
    func numberOfSections(in tableView: UITableView) -> Int {
        return filtering() ? filter.count : list.count
    }

    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        // If a section has no row, don't show its header
        let data = filtering() ? filter[section] : list[section]
        return data.rows.isEmpty ? nil : data.title
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return filtering() ? filter[section].rows.count : list[section].rows.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "library", for: indexPath)
        let data = filtering() ? filter[indexPath.section].rows[indexPath.row]
                               : list[indexPath.section].rows[indexPath.row]
        cell.textLabel!.text = data.name
        return cell
    }

    func sectionIndexTitles(for tableView: UITableView) -> [String]? {
        return filtering() ? filter.map { $0.title } : list.map { $0.title }
    }

    // MARK: - Segues
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "transporter" {
            if let indexPath = tableView.indexPathForSelectedRow {
                let selected = filtering() ? filter[indexPath.section].rows[indexPath.row]
                                           : list[indexPath.section].rows[indexPath.row]
                let controller = (segue.destination as! Detail)

                // This assumes you change `controller.result` to have type TableRow
                controller.result = selected
            }
        }
    }

    // search filter
    func filterContent(_ searchText: String) {
        let query = searchText.lowercased()

        filter = list.compactMap { section in
            let matchingRows = section.rows.filter { $0.name.lowercased().contains(query) }
            return matchingRows.isEmpty ? nil : TableSection(title: section.title, rows: matchingRows)
        }
        tableView.reloadData()
    }

    func searchEmpty() -> Bool {
        return search.searchBar.text?.isEmpty ?? true
    }

    func filtering() -> Bool {
        return search.isActive && (!searchEmpty())
    }
}
Run Code Online (Sandbox Code Playgroud)

结果:

英语:

英语

意大利语:

意大利语

斯洛伐克语:

斯洛伐克语

(我从谷歌翻译那里得到了翻译,所以如果有任何词不合适,我提前道歉——我不会说意大利语或斯洛伐克语)