在 SwiftUI 中动态创建列表部分
Dynamically create section for list in SwiftUI
我正在尝试在 SwiftUI 中使用 header 为 List
动态创建部分。
这是我的数组:
var lists = [a list of names with A to Z] // array of strings
然后我尝试获取第一个字母:
var firstCharacters: [Character] {
var firstCharacters = [Character]()
for list in lists.sorted(by: {[=11=] < }) {
if let character = list.first, !firstCharacters.contains(character) {
firstCharacters.append(character)
}
}
return firstCharacters
}
我这样创建了 list
:
List {
ForEach(firstCharacters, id: \.self) { charachter in
Section(header: Text("\(charachter.description)")) {
ForEach(Array(lists.enumerated()), id:\.element) { index, element in
Text("Name \(element), Id: \(index)")
})
}
}
}
}
现在我在向列表中添加部分时遇到问题,现在确定如何与列表合并。
以下将打印每个部分中的名称:
struct ContactsView: View {
let names = ["James", "Steve", "Anna", "Baxter", "Greg", "Zendy", "Astro", "Jenny"]
var firstChar: [Character] {
let array = names
.compactMap({ [=10=].first })
// Set is just a quick way to remove duplicates.
return Array(Set(array))
.sorted(by: { [=10=] < })
}
var body: some View {
List {
ForEach(firstChar, id: \.self) { char in
Section(header: Text("\(char.description)")) {
ForEach(names, id: \.self) { name in
if name.first == char {
Text(name)
}
}
}
}
}
}
}
尽管更好的方法可能是不使用 2 个不同的数组,而是将它们合并成一个,其中第一个字母是键,值是名称。
这样您就不必遍历每个部分的每个名称。
一个更好的分割方法是把你的单词列表变成一个以第一个字母为关键字的字典,如下所示:
var wordDict: [String:[String]] {
let letters = Set(lists.compactMap( { [=10=].first } ))
var dict: [String:[String]] = [:]
for letter in letters {
dict[String(letter)] = lists.filter( { [=10=].first == letter } ).sorted()
}
return dict
}
然后像这样在 List
中使用 Dict
:
List {
// You then make an array of keys, sorted by lowest to highest
ForEach(Array(wordDict.keys).sorted(by: <), id: \.self) { character in
Section(header: Text("\(character)")) {
// Because a dictionary lookup can return nil, we need to provide a response
// if it fails. I used [""], though I could have just force unwrapped.
ForEach(wordDict[character] ?? [""], id: \.self) { word in
Text("Name \(word)")
}
}
}
}
这样您就不必为每个字母遍历整个列表。它在创建 Dict
时完成一次。您不再需要 var firstChar
.
我的推荐是一个视图模型,它将一个字符串数组分组到一个 Section
结构中 Dictionary(grouping:by:)
class ViewModel : ObservableObject {
struct Section: Identifiable {
let letter : String
let names : [String]
var id : String { letter }
}
@Published var sections = [Section]()
var names = [String]() {
didSet {
let grouped = Dictionary(grouping: names, by: {[=10=].prefix(1)})
sections = grouped.keys.sorted().map{Section(letter: String([=10=]), names: grouped[[=10=]]!)}
}
}
}
只要数组的内容被修改,部分数组(和视图)就会更新。
在 onAppear
的视图中传递 一些 名称
struct ContentView: View {
@StateObject private var model = ViewModel()
var body: some View {
List(model.sections) { section in
Section(section.letter) {
ForEach(section.names, id: \.self, content: Text.init)
}
}
.onAppear {
model.names = ["Aaran", "Aaren", "Aarez", "Badsha", "Bailee", "Bailey", "Bailie", "Bailley", "Carlos", "Carrich", "Carrick", "Carson", "Carter", "Carwyn", "Dante", "Danyal", "Danyil", "Danys", "Daood", "Dara", "Darach", "Daragh", "Darcy", "D'arcy", "Dareh", "Eisa", "Eli", "Elias", "Elijah", "Eliot", "Elisau", "Finn", "Finnan", "Finnean", "Finnen", "Finnlay", "Geoff", "Geoffrey", "Geomer", "Geordan", "Hamad", "Hamid", "Hamish", "Hamza", "Hamzah", "Han", "Idris", "Iestyn", "Ieuan", "Igor", "Ihtisham", "Jarno", "Jarred", "Jarvi", "Jasey-Jay", "Jasim", "Jaskaran", "Jason", "Jasper", "Jaxon", "Kabeer", "Kabir", "Kacey", "Kacper", "Kade", "Kaden", "Kadin", "Kadyn", "Kaeden", "Kael", "Kaelan", "Kaelin", "Kaelum", "Kai", "Kaid", "Kaidan", "Kaiden", "Kaidinn", "Kaidyn", "Kaileb", "Kailin", "Karsyn", "Karthikeya", "Kasey", "Kash", "Kashif", "Kasim", "Kasper", "Kasra", "Kavin", "Kayam", "Leiten", "Leithen", "Leland", "Lenin", "Lennan", "Lennen", "Lennex", "Lennon", "Lennox", "Lenny", "Leno", "Lenon", "Lenyn", "Leo", "Leon", "Leonard", "Leonardas", "Leonardo", "Lepeng", "Leroy", "Leven", "Levi", "Levon", "Machlan", "Maciej", "Mack", "Mackenzie", "Mackenzy", "Mackie", "Macsen", "Macy", "Madaki", "Nickson", "Nicky", "Nico", "Nicodemus", "Nicol", "Nicolae", "Nicolas", "Nidhish", "Nihaal", "Nihal", "Nikash", "Olaoluwapolorimi", "Ole", "Olie", "Oliver", "Olivier", "Peter", "Phani", "Philip", "Philippos", "Phinehas", "Phoenix", "Phoevos", "Pierce", "Pierre-Antoine", "Pieter", "Pietro", "Piotr", "Porter", "Prabhjoit", "Prabodhan", "Praise", "Pranav", "Rasul", "Raul", "Raunaq", "Ravin", "Ray", "Rayaan", "Rayan", "Rayane", "Rayden", "Rayhan", "Santiago", "Santino", "Satveer", "Saul", "Saunders", "Savin", "Sayad", "Sayeed", "Sayf", "Scot", "Scott", "Scott-Alexander", "Seaan", "Seamas", "Seamus", "Sean", "Seane", "Sean-James", "Sean-Paul", "Sean-Ray", "Seb", "Sebastian", "Sebastien", "Selasi", "Seonaidh", "Sephiroth", "Sergei", "Sergio", "Seth", "Sethu", "Seumas", "Shaarvin", "Shadow", "Shae", "Shahmir", "Shai", "Shane", "Shannon", "Sharland", "Sharoz", "Shaughn", "Shaun", "Tadhg", "Taegan", "Taegen", "Tai", "Tait", "Uilleam", "Umair", "Umar", "Umer", "Umut", "Urban", "Uri", "Usman", "Uzair", "Uzayr", "Valen", "Valentin", "Valentino", "Valery", "Valo", "Vasyl", "Vedantsinh", "Veeran", "Victor", "Victory", "Vinay", "Vince", "Wen", "Wesley", "Wesley-Scott", "Wiktor", "Wilkie", "Will", "William", "William-John", "Willum", "Wilson", "Windsor", "Wojciech", "Woyenbrakemi", "Wyatt", "Wylie", "Wynn", "Xabier", "Xander", "Xavier", "Xiao", "Xida", "Xin", "Xue", "Yadgor", "Yago", "Yahya", "Yakup", "Yang", "Yanick", "Yann", "Yannick", "Yaseen", "Yasin", "Yasir", "Yassin", "Yoji", "Yong", "Yoolgeun", "Yorgos", "Youcef", "Yousif", "Youssef", "Yu", "Yuanyu", "Yuri", "Yusef", "Yusuf", "Yves", "Zaaine", "Zaak", "Zac", "Zach", "Zachariah", "Zacharias", "Ziyaan", "Zohaib", "Zohair", "Zoubaeir", "Zubair", "Zubayr", "Zuriel"]
}
}
}
我正在尝试在 SwiftUI 中使用 header 为 List
动态创建部分。
这是我的数组:
var lists = [a list of names with A to Z] // array of strings
然后我尝试获取第一个字母:
var firstCharacters: [Character] {
var firstCharacters = [Character]()
for list in lists.sorted(by: {[=11=] < }) {
if let character = list.first, !firstCharacters.contains(character) {
firstCharacters.append(character)
}
}
return firstCharacters
}
我这样创建了 list
:
List {
ForEach(firstCharacters, id: \.self) { charachter in
Section(header: Text("\(charachter.description)")) {
ForEach(Array(lists.enumerated()), id:\.element) { index, element in
Text("Name \(element), Id: \(index)")
})
}
}
}
}
现在我在向列表中添加部分时遇到问题,现在确定如何与列表合并。
以下将打印每个部分中的名称:
struct ContactsView: View {
let names = ["James", "Steve", "Anna", "Baxter", "Greg", "Zendy", "Astro", "Jenny"]
var firstChar: [Character] {
let array = names
.compactMap({ [=10=].first })
// Set is just a quick way to remove duplicates.
return Array(Set(array))
.sorted(by: { [=10=] < })
}
var body: some View {
List {
ForEach(firstChar, id: \.self) { char in
Section(header: Text("\(char.description)")) {
ForEach(names, id: \.self) { name in
if name.first == char {
Text(name)
}
}
}
}
}
}
}
尽管更好的方法可能是不使用 2 个不同的数组,而是将它们合并成一个,其中第一个字母是键,值是名称。
这样您就不必遍历每个部分的每个名称。
一个更好的分割方法是把你的单词列表变成一个以第一个字母为关键字的字典,如下所示:
var wordDict: [String:[String]] {
let letters = Set(lists.compactMap( { [=10=].first } ))
var dict: [String:[String]] = [:]
for letter in letters {
dict[String(letter)] = lists.filter( { [=10=].first == letter } ).sorted()
}
return dict
}
然后像这样在 List
中使用 Dict
:
List {
// You then make an array of keys, sorted by lowest to highest
ForEach(Array(wordDict.keys).sorted(by: <), id: \.self) { character in
Section(header: Text("\(character)")) {
// Because a dictionary lookup can return nil, we need to provide a response
// if it fails. I used [""], though I could have just force unwrapped.
ForEach(wordDict[character] ?? [""], id: \.self) { word in
Text("Name \(word)")
}
}
}
}
这样您就不必为每个字母遍历整个列表。它在创建 Dict
时完成一次。您不再需要 var firstChar
.
我的推荐是一个视图模型,它将一个字符串数组分组到一个 Section
结构中 Dictionary(grouping:by:)
class ViewModel : ObservableObject {
struct Section: Identifiable {
let letter : String
let names : [String]
var id : String { letter }
}
@Published var sections = [Section]()
var names = [String]() {
didSet {
let grouped = Dictionary(grouping: names, by: {[=10=].prefix(1)})
sections = grouped.keys.sorted().map{Section(letter: String([=10=]), names: grouped[[=10=]]!)}
}
}
}
只要数组的内容被修改,部分数组(和视图)就会更新。
在 onAppear
的视图中传递 一些 名称
struct ContentView: View {
@StateObject private var model = ViewModel()
var body: some View {
List(model.sections) { section in
Section(section.letter) {
ForEach(section.names, id: \.self, content: Text.init)
}
}
.onAppear {
model.names = ["Aaran", "Aaren", "Aarez", "Badsha", "Bailee", "Bailey", "Bailie", "Bailley", "Carlos", "Carrich", "Carrick", "Carson", "Carter", "Carwyn", "Dante", "Danyal", "Danyil", "Danys", "Daood", "Dara", "Darach", "Daragh", "Darcy", "D'arcy", "Dareh", "Eisa", "Eli", "Elias", "Elijah", "Eliot", "Elisau", "Finn", "Finnan", "Finnean", "Finnen", "Finnlay", "Geoff", "Geoffrey", "Geomer", "Geordan", "Hamad", "Hamid", "Hamish", "Hamza", "Hamzah", "Han", "Idris", "Iestyn", "Ieuan", "Igor", "Ihtisham", "Jarno", "Jarred", "Jarvi", "Jasey-Jay", "Jasim", "Jaskaran", "Jason", "Jasper", "Jaxon", "Kabeer", "Kabir", "Kacey", "Kacper", "Kade", "Kaden", "Kadin", "Kadyn", "Kaeden", "Kael", "Kaelan", "Kaelin", "Kaelum", "Kai", "Kaid", "Kaidan", "Kaiden", "Kaidinn", "Kaidyn", "Kaileb", "Kailin", "Karsyn", "Karthikeya", "Kasey", "Kash", "Kashif", "Kasim", "Kasper", "Kasra", "Kavin", "Kayam", "Leiten", "Leithen", "Leland", "Lenin", "Lennan", "Lennen", "Lennex", "Lennon", "Lennox", "Lenny", "Leno", "Lenon", "Lenyn", "Leo", "Leon", "Leonard", "Leonardas", "Leonardo", "Lepeng", "Leroy", "Leven", "Levi", "Levon", "Machlan", "Maciej", "Mack", "Mackenzie", "Mackenzy", "Mackie", "Macsen", "Macy", "Madaki", "Nickson", "Nicky", "Nico", "Nicodemus", "Nicol", "Nicolae", "Nicolas", "Nidhish", "Nihaal", "Nihal", "Nikash", "Olaoluwapolorimi", "Ole", "Olie", "Oliver", "Olivier", "Peter", "Phani", "Philip", "Philippos", "Phinehas", "Phoenix", "Phoevos", "Pierce", "Pierre-Antoine", "Pieter", "Pietro", "Piotr", "Porter", "Prabhjoit", "Prabodhan", "Praise", "Pranav", "Rasul", "Raul", "Raunaq", "Ravin", "Ray", "Rayaan", "Rayan", "Rayane", "Rayden", "Rayhan", "Santiago", "Santino", "Satveer", "Saul", "Saunders", "Savin", "Sayad", "Sayeed", "Sayf", "Scot", "Scott", "Scott-Alexander", "Seaan", "Seamas", "Seamus", "Sean", "Seane", "Sean-James", "Sean-Paul", "Sean-Ray", "Seb", "Sebastian", "Sebastien", "Selasi", "Seonaidh", "Sephiroth", "Sergei", "Sergio", "Seth", "Sethu", "Seumas", "Shaarvin", "Shadow", "Shae", "Shahmir", "Shai", "Shane", "Shannon", "Sharland", "Sharoz", "Shaughn", "Shaun", "Tadhg", "Taegan", "Taegen", "Tai", "Tait", "Uilleam", "Umair", "Umar", "Umer", "Umut", "Urban", "Uri", "Usman", "Uzair", "Uzayr", "Valen", "Valentin", "Valentino", "Valery", "Valo", "Vasyl", "Vedantsinh", "Veeran", "Victor", "Victory", "Vinay", "Vince", "Wen", "Wesley", "Wesley-Scott", "Wiktor", "Wilkie", "Will", "William", "William-John", "Willum", "Wilson", "Windsor", "Wojciech", "Woyenbrakemi", "Wyatt", "Wylie", "Wynn", "Xabier", "Xander", "Xavier", "Xiao", "Xida", "Xin", "Xue", "Yadgor", "Yago", "Yahya", "Yakup", "Yang", "Yanick", "Yann", "Yannick", "Yaseen", "Yasin", "Yasir", "Yassin", "Yoji", "Yong", "Yoolgeun", "Yorgos", "Youcef", "Yousif", "Youssef", "Yu", "Yuanyu", "Yuri", "Yusef", "Yusuf", "Yves", "Zaaine", "Zaak", "Zac", "Zach", "Zachariah", "Zacharias", "Ziyaan", "Zohaib", "Zohair", "Zoubaeir", "Zubair", "Zubayr", "Zuriel"]
}
}
}