如何使用 mutable 数据源在 table 视图中按字母顺序制作部分 headers
How to make alphabetically section headers in table view with a mutable data source
我将视图控制器的字符串存储在字符串数组中。我在 table 视图中将此字符串数组作为数据源导入。这一切都很顺利。但现在我想对 table 视图进行排序并添加部分 headers。 header 部分应该来自字母表,含义部分的行应该是数组中的所有字符串,以部分 header.
的字母开头
我知道如何使用静态数组实现这一点。但是我怎样才能只显示部分,其中也有行(数组中的字符串)?我怎样才能让它在保存带有字母的新字符串时生成一个新的部分,该字母在部分中尚不存在?
希望我已经解释得够准确了。我尝试了很长时间来解决这个问题。如果有人能帮助我就太好了。
以下是一些代码片段:
class OverViewController: UIViewController {
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var addButton: UIBarButtonItem!
@IBOutlet weak var editButton: UINavigationItem!
var kontaktListe = Telefonbuch.loadArray()
var sections = [[String]]()
var collation = UILocalizedIndexedCollation.currentCollation()
override func viewDidLoad()
{
super.viewDidLoad()
tableView.dataSource = self
configureSectionData()
tableView.reloadData()
}
func configureSectionData()
{
let names = kontaktListe.map{[=12=].name}
let selector: Selector = "description"
sections = Array(count:collation.sectionTitles.count, repeatedValue: [])
let sortedObjects = collation.sortedArrayFromArray(names, collationStringSelector: selector)
for object in sortedObjects {
let sectionNumber = collation.sectionForObject(object, collationStringSelector: selector)
sections[sectionNumber].append(object as! String)
}
}
我加载 object var kontaktListe = Telefonbuch.loadArray()
并获取名称 属性 let names = kontaktListe.map{[=14=].name}
。我想从那里获取要排序和添加的字符串。
我会将您存储联系人的方式更改为以首字母作为键的字典,并将与该首字母对应的姓名放入子数组中:
contacts = ["A": ["Anton", "Anna"], "C": ["Caesar"]]
我这里简化了联系人的方式(以字符串的形式),但是你明白了。
我还会将字母的节号保存在一个单独的数组中,如下所示:
letters = ["A", "C"]
保持数组排序和组织,所以在每个 insertion/deletion/update 之后检查。这不是 table 视图实现的一部分。我会让 Viewcontroller 成为电话簿的代表,这样你就可以从电话簿中触发一个 update-like 方法来更新 table.
如何获取数据源的数据:
节数:
letters.count
索引 i 处的章节标题是
letters[i]
第i节的单元格数是
contacts[letters[i]].count
第 i 部分中特定单元格 c 的内容是:
contacts[letters[i]][c]
如果还有什么不明白的地方,请随时提出进一步的问题。
更新 - 如何生成数组:
我不需要对数据进行排序,如果你传递的数据已经排序,你可以删除下面的排序行...
let data = ["Anton", "Anna", "John", "Caesar"] // Example data, use your phonebook data here.
// Build letters array:
var letters: [Character]
letters = data.map { (name) -> Character in
return name[name.startIndex]
}
letters = letters.sort()
letters = letters.reduce([], combine: { (list, name) -> [Character] in
if !list.contains(name) {
return list + [name]
}
return list
})
// Build contacts array:
var contacts = [Character: [String]]()
for entry in data {
if contacts[entry[entry.startIndex]] == nil {
contacts[entry[entry.startIndex]] = [String]()
}
contacts[entry[entry.startIndex]]!.append(entry)
}
for (letter, list) in contacts {
list.sort()
}
对于Swift 3:
let data = ["Anton", "Anna", "John", "Caesar"] // Example data, use your phonebook data here.
// Build letters array:
var letters: [Character]
letters = data.map { (name) -> Character in
return name[name.startIndex]
}
letters = letters.sorted()
letters = letters.reduce([], { (list, name) -> [Character] in
if !list.contains(name) {
return list + [name]
}
return list
})
// Build contacts array:
var contacts = [Character: [String]]()
for entry in data {
if contacts[entry[entry.startIndex]] == nil {
contacts[entry[entry.startIndex]] = [String]()
}
contacts[entry[entry.startIndex]]!.append(entry)
}
for (letter, list) in contacts {
contacts[letter] = list.sorted()
}
我运行 playground 中的代码得到了
的以下输出
字母:
["A", "C", "J"]
联系人:
["J": ["John"], "C": ["Caesar"], "A": ["Anton", "Anna"]]
为Swift3。谢谢@Stefan!这是我使用 Set
的版本
var tableViewSource: [Character : [String]]!
var tableViewHeaders: [Character]!
let data = ["Anton", "Anna", "John", "Caesar"]
func createTableData(wordList: [String]) -> (firstSymbols: [Character], source: [Character : [String]]) {
// Build Character Set
var firstSymbols = Set<Character>()
func getFirstSymbol(word: String) -> Character {
return word[word.startIndex]
}
wordList.forEach {_ = firstSymbols.insert(getFirstSymbol(word: [=10=])) }
// Build tableSourse array
var tableViewSourse = [Character : [String]]()
for symbol in firstSymbols {
var words = [String]()
for word in wordList {
if symbol == getFirstSymbol(word: word) {
words.append(word)
}
}
tableViewSourse[symbol] = words.sorted(by: {[=10=] < })
}
let sortedSymbols = firstSymbols.sorted(by: {[=10=] < })
return (sortedSymbols, tableViewSourse)
}
func getTableData(words: [String]) {
tableViewSource = createTableData(wordList: words).source
tableViewHeaders = createTableData(wordList: words).firstSymbols
}
getTableData(words: data)
print(tableViewSource) // ["J": ["John"], "C": ["Caesar"], "A": ["Anna", "Anton"]]
print(tableViewHeaders) // ["A", "C", "J"]
我是在一个循环内完成的,不少(Swift 4):
struct ContactData {
let longName: String
let phones: [String]
let thumbnailImageData: Data?
}
var contacts = [ContactData]()
var tableViewSource = [Character : [ContactData]]()
var headerTitles = [Character]()
func createContactsData(completionHandler: @escaping () -> Swift.Void) {
contacts = extractContacts() // convert CNContact to custom ContactData
tableViewSource.removeAll()
var prevChar: Character?
var currentBatch: [ContactData]!
contacts.forEach { contact in
guard let firstChar = contact.longName.first else {
return
}
if prevChar != firstChar {
if prevChar != nil {
tableViewSource[prevChar!] = currentBatch
}
prevChar = firstChar
currentBatch = [ContactData]()
}
currentBatch.append(contact)
}
let allKeys = Array(tableViewSource.keys)
let sortedSymbols = allKeys.sorted(by: {[=10=] < })
headerTitles = sortedSymbols
completionHandler()
}
我将视图控制器的字符串存储在字符串数组中。我在 table 视图中将此字符串数组作为数据源导入。这一切都很顺利。但现在我想对 table 视图进行排序并添加部分 headers。 header 部分应该来自字母表,含义部分的行应该是数组中的所有字符串,以部分 header.
的字母开头我知道如何使用静态数组实现这一点。但是我怎样才能只显示部分,其中也有行(数组中的字符串)?我怎样才能让它在保存带有字母的新字符串时生成一个新的部分,该字母在部分中尚不存在?
希望我已经解释得够准确了。我尝试了很长时间来解决这个问题。如果有人能帮助我就太好了。
以下是一些代码片段:
class OverViewController: UIViewController {
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var addButton: UIBarButtonItem!
@IBOutlet weak var editButton: UINavigationItem!
var kontaktListe = Telefonbuch.loadArray()
var sections = [[String]]()
var collation = UILocalizedIndexedCollation.currentCollation()
override func viewDidLoad()
{
super.viewDidLoad()
tableView.dataSource = self
configureSectionData()
tableView.reloadData()
}
func configureSectionData()
{
let names = kontaktListe.map{[=12=].name}
let selector: Selector = "description"
sections = Array(count:collation.sectionTitles.count, repeatedValue: [])
let sortedObjects = collation.sortedArrayFromArray(names, collationStringSelector: selector)
for object in sortedObjects {
let sectionNumber = collation.sectionForObject(object, collationStringSelector: selector)
sections[sectionNumber].append(object as! String)
}
}
我加载 object var kontaktListe = Telefonbuch.loadArray()
并获取名称 属性 let names = kontaktListe.map{[=14=].name}
。我想从那里获取要排序和添加的字符串。
我会将您存储联系人的方式更改为以首字母作为键的字典,并将与该首字母对应的姓名放入子数组中:
contacts = ["A": ["Anton", "Anna"], "C": ["Caesar"]]
我这里简化了联系人的方式(以字符串的形式),但是你明白了。
我还会将字母的节号保存在一个单独的数组中,如下所示:
letters = ["A", "C"]
保持数组排序和组织,所以在每个 insertion/deletion/update 之后检查。这不是 table 视图实现的一部分。我会让 Viewcontroller 成为电话簿的代表,这样你就可以从电话簿中触发一个 update-like 方法来更新 table.
如何获取数据源的数据:
节数:
letters.count
索引 i 处的章节标题是
letters[i]
第i节的单元格数是
contacts[letters[i]].count
第 i 部分中特定单元格 c 的内容是:
contacts[letters[i]][c]
如果还有什么不明白的地方,请随时提出进一步的问题。
更新 - 如何生成数组:
我不需要对数据进行排序,如果你传递的数据已经排序,你可以删除下面的排序行...
let data = ["Anton", "Anna", "John", "Caesar"] // Example data, use your phonebook data here.
// Build letters array:
var letters: [Character]
letters = data.map { (name) -> Character in
return name[name.startIndex]
}
letters = letters.sort()
letters = letters.reduce([], combine: { (list, name) -> [Character] in
if !list.contains(name) {
return list + [name]
}
return list
})
// Build contacts array:
var contacts = [Character: [String]]()
for entry in data {
if contacts[entry[entry.startIndex]] == nil {
contacts[entry[entry.startIndex]] = [String]()
}
contacts[entry[entry.startIndex]]!.append(entry)
}
for (letter, list) in contacts {
list.sort()
}
对于Swift 3:
let data = ["Anton", "Anna", "John", "Caesar"] // Example data, use your phonebook data here.
// Build letters array:
var letters: [Character]
letters = data.map { (name) -> Character in
return name[name.startIndex]
}
letters = letters.sorted()
letters = letters.reduce([], { (list, name) -> [Character] in
if !list.contains(name) {
return list + [name]
}
return list
})
// Build contacts array:
var contacts = [Character: [String]]()
for entry in data {
if contacts[entry[entry.startIndex]] == nil {
contacts[entry[entry.startIndex]] = [String]()
}
contacts[entry[entry.startIndex]]!.append(entry)
}
for (letter, list) in contacts {
contacts[letter] = list.sorted()
}
我运行 playground 中的代码得到了
的以下输出字母:
["A", "C", "J"]
联系人:
["J": ["John"], "C": ["Caesar"], "A": ["Anton", "Anna"]]
为Swift3。谢谢@Stefan!这是我使用 Set
的版本var tableViewSource: [Character : [String]]!
var tableViewHeaders: [Character]!
let data = ["Anton", "Anna", "John", "Caesar"]
func createTableData(wordList: [String]) -> (firstSymbols: [Character], source: [Character : [String]]) {
// Build Character Set
var firstSymbols = Set<Character>()
func getFirstSymbol(word: String) -> Character {
return word[word.startIndex]
}
wordList.forEach {_ = firstSymbols.insert(getFirstSymbol(word: [=10=])) }
// Build tableSourse array
var tableViewSourse = [Character : [String]]()
for symbol in firstSymbols {
var words = [String]()
for word in wordList {
if symbol == getFirstSymbol(word: word) {
words.append(word)
}
}
tableViewSourse[symbol] = words.sorted(by: {[=10=] < })
}
let sortedSymbols = firstSymbols.sorted(by: {[=10=] < })
return (sortedSymbols, tableViewSourse)
}
func getTableData(words: [String]) {
tableViewSource = createTableData(wordList: words).source
tableViewHeaders = createTableData(wordList: words).firstSymbols
}
getTableData(words: data)
print(tableViewSource) // ["J": ["John"], "C": ["Caesar"], "A": ["Anna", "Anton"]]
print(tableViewHeaders) // ["A", "C", "J"]
我是在一个循环内完成的,不少(Swift 4):
struct ContactData {
let longName: String
let phones: [String]
let thumbnailImageData: Data?
}
var contacts = [ContactData]()
var tableViewSource = [Character : [ContactData]]()
var headerTitles = [Character]()
func createContactsData(completionHandler: @escaping () -> Swift.Void) {
contacts = extractContacts() // convert CNContact to custom ContactData
tableViewSource.removeAll()
var prevChar: Character?
var currentBatch: [ContactData]!
contacts.forEach { contact in
guard let firstChar = contact.longName.first else {
return
}
if prevChar != firstChar {
if prevChar != nil {
tableViewSource[prevChar!] = currentBatch
}
prevChar = firstChar
currentBatch = [ContactData]()
}
currentBatch.append(contact)
}
let allKeys = Array(tableViewSource.keys)
let sortedSymbols = allKeys.sorted(by: {[=10=] < })
headerTitles = sortedSymbols
completionHandler()
}