swift - 此用例中的 UILocalizedIndexedCollat​​ion

标签 swift tableview

如何在这个用例中将节标题索引列表添加到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

}

现在要翻译的是表格数据。

注意

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

节标题和索引列表的通常实现会产生类似的结果

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

T                 // table in
Übersetzung       // another language
Getriebe
...

What's the correct model for UILocalizedIndexedCollation?


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

感谢您的帮助!

最佳答案

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


我认为 UILocalizedIndexedCollat​​ion 比滚动您自己的数据模型更令人困惑。您需要 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
    }
}

之后,填充和过滤表格就非常容易了:

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())
    }
}

结果:

英语:

English

意大利语:

Italian

斯洛伐克语:

Slovak

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

关于swift - 此用例中的 UILocalizedIndexedCollat​​ion,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51686467/

相关文章:

JavaFX TableView 使用复选框来填充列表

ios - 如何使用主视图的选定单元格内容设置详细 View 的表格 View 的最顶层单元格(第一行)?

qt - 如何在鼠标单击 QtQuick2 TableView 时获取列号

swift - 如何将修改后的结果作为 promise 返回 promise

swift - 加速度计检测手机运动

swift - 在/Users/Shared/- 使用 Swift 创建一个目录

ios - Swift - 如何在约束中动态更改 textView 高度?

ios - swift/ios 如何检查我的 TableView 是否嵌入在 uitableview Controller 实例中?

ios - 我如何利用 PageViewController 根据用户的输入生成新的页面 View ?

ios - 逐步下载 Firebase child iOS