将数据过滤到包含部分的列表中
Filtering data into a list with sections
我有按优先级排序的数据。我正在尝试将该数据显示在列表中:
priority 1
item with that priority
item with that priority
priority 2
item with that priority
item with that priority
所以我想用 list
和 sections
来显示优先级,然后在具有该优先级的每个项目下列出。
struct PriorityView: View {
@EnvironmentObject private var taskdata: DataModel
@State var byPriotity: Int
var body: some View {
List {
VStack(alignment: .leading, spacing: 12) {
// priority 3 is display all items in the list
if byPriotity == 3 {
ForEach(taskdata.filteredTasks(byPriority: byPriotity), id: \.id) { task in
Section(header: Text(getTitle(byPriority: task.priority)).font(.headline)) {
Text(task.title)
}
}
}
}
}
}
}
这只是创建一个列表,其中的一个部分显示优先级,然后是项目的标题。这不是我想要输出的。
我开始阅读有关 section
的文章,一些文章 (this, this, and ) 提供了一些很好的建议,但我一直在试图弄清楚如何迭代并找到具有特定优先级的所有项目,创建一个 header,然后列出所有这些项目的标题。也许我应该添加第二个 forEach
过滤具有特定优先级的所有项目?还是将初始过滤保存在一个变量中,然后对其进行过滤?我不知道。
我试过
ForEach(taskdata.filteredTasks(byPriority: 3)) { task in
Section(header: Text(getTitle(byPriority: task.priority)).font(.headline)) {
ForEach(task.priority.filter {[=12=].contains(byPriotity) || byPriotity.isEmpty}) {
Text(task.title)
}
}
}
但我不能那样过滤它们。 Int 没有 filter
然后我尝试了
ForEach(task.priority.isEqual(to: byPriotity))
再一次,int 没有 isEqual
的问题。我要在这里兜圈子...
这是我正在尝试的代码:
struct Task: Codable, Hashable, Identifiable {
var id = UUID()
var title: String
var priority = 2
}
extension Array: RawRepresentable where Element: Codable {
public init?(rawValue: String) {
guard let data = rawValue.data(using: .utf8),
let result = try? JSONDecoder().decode([Element].self, from: data)
else {
return nil
}
self = result
}
public var rawValue: String {
guard let data = try? JSONEncoder().encode(self), // comment all this out
let result = String(data: data, encoding: .utf8)
else {
return "[]"
}
return result
}
}
final class DataModel: ObservableObject {
@AppStorage("tasksp") public var tasks: [Task] = []
init() {
self.tasks = self.tasks.sorted(by: {
[=13=].priority < .priority
})
}
func sortList() {
self.tasks = self.tasks.sorted(by: {
[=13=].priority < .priority
})
}
func filteredTasks(byPriority priority: Int) -> [Task] {
tasks.filter { priority == 3 || [=13=].priority == priority }
}
}
struct PriorityView: View {
@EnvironmentObject private var taskdata: DataModel
@State var byPriotity: Int
var body: some View {
List {
VStack(alignment: .leading, spacing: 12) {
// priority 3 is display all items in the list
// I'm going to add another view so the user can
// can select what to display eventually
if byPriotity == 3 {
ForEach(taskdata.filteredTasks(byPriority: byPriotity), id: \.id) { task in
Section(header: Text(getTitle(byPriority: task.priority)).font(.headline)) {
Text(task.title)
}
}
}
}
}
}
func getTitle(byPriority:Int) -> String {
switch byPriority {
case 0: return "Important"
case 1: return "Tomorrow"
default: return "Someday"
}
}
}
编辑:
尝试使用 vadian 建议的代码。我真的不知道我在做什么,但是试过了,结果是这样的:
将结构名称更改为:
struct SectionOrdered : Identifiable {
var id: String { priority }
let priority: String
let tasks: [Task]
}
我试过的代码是:
List {
VStack(alignment: .leading, spacing: 12) {
if byPriority == 3 {
ForEach(taskdata.sections) { task in
Section(header: task.priority) {
Text(task.title)
}
}
}
}
}
vadian 建议过滤 class 中的所有内容,但我不知道如何使用它。我试过了,但我把这里弄得更糟了。
我想知道这是否可能。
要将您的数据分组,首先创建一个结构 Section
struct Section : Identifiable {
var id : String { priority }
let priority : String
let tasks : [Task]
}
并在视图模型中 发布 部分并将它们分组,例如在 init
方法中。
final class DataModel: ObservableObject {
@AppStorage("tasksp") public var tasks: [Task] = []
@Published var sections = [Section]()
init() {
let grouped = Dictionary(grouping: tasks, by: \.priority)
let sortedKeys = grouped.keys.sorted()
self.sections = sortedKeys.map{Section(priority: getTitle(byPriority: [=11=]), tasks: grouped[[=11=]]!)}
}
func getTitle(byPriority: Int) -> String {
switch byPriority {
case 0: return "Important"
case 1: return "Tomorrow"
default: return "Someday"
}
}
....
好处是将所有不必要的数据处理都排除在视图之外。
在视图中显示数据
ForEach(taskdata.sections) { section in
Section {
ForEach(section.tasks) { task in
Text(task.title)
}
} header: {
Text(section.priority)
.font(.headline)
}
}
如果您想将过滤后的数据分组到多个部分,请先过滤然后再分组。
我有按优先级排序的数据。我正在尝试将该数据显示在列表中:
priority 1
item with that priority
item with that priority
priority 2
item with that priority
item with that priority
所以我想用 list
和 sections
来显示优先级,然后在具有该优先级的每个项目下列出。
struct PriorityView: View {
@EnvironmentObject private var taskdata: DataModel
@State var byPriotity: Int
var body: some View {
List {
VStack(alignment: .leading, spacing: 12) {
// priority 3 is display all items in the list
if byPriotity == 3 {
ForEach(taskdata.filteredTasks(byPriority: byPriotity), id: \.id) { task in
Section(header: Text(getTitle(byPriority: task.priority)).font(.headline)) {
Text(task.title)
}
}
}
}
}
}
}
这只是创建一个列表,其中的一个部分显示优先级,然后是项目的标题。这不是我想要输出的。
我开始阅读有关 section
的文章,一些文章 (this, this, and forEach
过滤具有特定优先级的所有项目?还是将初始过滤保存在一个变量中,然后对其进行过滤?我不知道。
我试过
ForEach(taskdata.filteredTasks(byPriority: 3)) { task in
Section(header: Text(getTitle(byPriority: task.priority)).font(.headline)) {
ForEach(task.priority.filter {[=12=].contains(byPriotity) || byPriotity.isEmpty}) {
Text(task.title)
}
}
}
但我不能那样过滤它们。 Int 没有 filter
然后我尝试了
ForEach(task.priority.isEqual(to: byPriotity))
再一次,int 没有 isEqual
的问题。我要在这里兜圈子...
这是我正在尝试的代码:
struct Task: Codable, Hashable, Identifiable {
var id = UUID()
var title: String
var priority = 2
}
extension Array: RawRepresentable where Element: Codable {
public init?(rawValue: String) {
guard let data = rawValue.data(using: .utf8),
let result = try? JSONDecoder().decode([Element].self, from: data)
else {
return nil
}
self = result
}
public var rawValue: String {
guard let data = try? JSONEncoder().encode(self), // comment all this out
let result = String(data: data, encoding: .utf8)
else {
return "[]"
}
return result
}
}
final class DataModel: ObservableObject {
@AppStorage("tasksp") public var tasks: [Task] = []
init() {
self.tasks = self.tasks.sorted(by: {
[=13=].priority < .priority
})
}
func sortList() {
self.tasks = self.tasks.sorted(by: {
[=13=].priority < .priority
})
}
func filteredTasks(byPriority priority: Int) -> [Task] {
tasks.filter { priority == 3 || [=13=].priority == priority }
}
}
struct PriorityView: View {
@EnvironmentObject private var taskdata: DataModel
@State var byPriotity: Int
var body: some View {
List {
VStack(alignment: .leading, spacing: 12) {
// priority 3 is display all items in the list
// I'm going to add another view so the user can
// can select what to display eventually
if byPriotity == 3 {
ForEach(taskdata.filteredTasks(byPriority: byPriotity), id: \.id) { task in
Section(header: Text(getTitle(byPriority: task.priority)).font(.headline)) {
Text(task.title)
}
}
}
}
}
}
func getTitle(byPriority:Int) -> String {
switch byPriority {
case 0: return "Important"
case 1: return "Tomorrow"
default: return "Someday"
}
}
}
编辑:
尝试使用 vadian 建议的代码。我真的不知道我在做什么,但是试过了,结果是这样的:
将结构名称更改为:
struct SectionOrdered : Identifiable {
var id: String { priority }
let priority: String
let tasks: [Task]
}
我试过的代码是:
List {
VStack(alignment: .leading, spacing: 12) {
if byPriority == 3 {
ForEach(taskdata.sections) { task in
Section(header: task.priority) {
Text(task.title)
}
}
}
}
}
vadian 建议过滤 class 中的所有内容,但我不知道如何使用它。我试过了,但我把这里弄得更糟了。
我想知道这是否可能。
要将您的数据分组,首先创建一个结构 Section
struct Section : Identifiable {
var id : String { priority }
let priority : String
let tasks : [Task]
}
并在视图模型中 发布 部分并将它们分组,例如在 init
方法中。
final class DataModel: ObservableObject {
@AppStorage("tasksp") public var tasks: [Task] = []
@Published var sections = [Section]()
init() {
let grouped = Dictionary(grouping: tasks, by: \.priority)
let sortedKeys = grouped.keys.sorted()
self.sections = sortedKeys.map{Section(priority: getTitle(byPriority: [=11=]), tasks: grouped[[=11=]]!)}
}
func getTitle(byPriority: Int) -> String {
switch byPriority {
case 0: return "Important"
case 1: return "Tomorrow"
default: return "Someday"
}
}
....
好处是将所有不必要的数据处理都排除在视图之外。
在视图中显示数据
ForEach(taskdata.sections) { section in
Section {
ForEach(section.tasks) { task in
Text(task.title)
}
} header: {
Text(section.priority)
.font(.headline)
}
}
如果您想将过滤后的数据分组到多个部分,请先过滤然后再分组。