SwiftUI 中的多级列表

Multiple level List in SwiftUI

我正在 SwiftUI 中处理一个项目。我想创建类似的东西,

我目前使用的代码:

TaskListView

struct TaskListView: View {
    var tasks: [Task] = Task.all()
    
    var body: some View {
        List {
            ForEach(self.tasks) {task in
                TaskView(task: task)
            }
        }
    }
}

TaskView

struct TaskView: View {
    @ObservedObject var task: Task
    
    var body: some View {
        VStack {
            Text(task.name)
            .font(.custom("Avenir Next Regular", size: 14))
            
            //Here.................
            if !task.subtasks.isEmpty {
                Section {
                    ForEach(task.subtasks) {subtask in
                        TDTaskView(task: subtask)
                    }
                }.padding(.leading)
            }
        }
    }
}

Task 型号:

class Task: Identifiable, ObservableObject {
    var id: UUID = UUID()
    var name: String
    @Published var isCompleted: Bool = false
    var subtasks = [Task]()
    
    init(name: String, isCompleted: Bool = false, subtasks: [Task] = [Task]()) {
        self.name = name
        self.isCompleted = isCompleted
        self.subtasks = subtasks
    }
}

我尝试实现嵌套 List 的方式现在可以在选择上正常工作。我是不是执行错了?

您可以尝试递归地创建项目:

struct ContentView: View {
    var tasks: [Task] = Task.all()

    var body: some View {
        List {
            TaskListView(tasks: tasks)
        }
    }
}
struct TaskListView: View {
    var tasks: [Task]

    var body: some View {
        ForEach(tasks, id: \.id) { task in
            TaskView(task: task)
        }
    }
}
struct TaskView: View {
    @ObservedObject var task: Task

    var body: some View {
        VStack {
            HStack {
                Circle().stroke() // replace with a custom control
                    .frame(width: 20, height: 20)
                Text(task.name)
                    .font(.custom("Avenir Next Regular", size: 14))
                Spacer()
            }
            if !task.subtasks.isEmpty {
                TaskListView(tasks: task.subtasks)
                    .padding(.leading)
            }
        }
    }
}

你很接近,我想说只改变两件事。

首先,将 VStack 更改为 Group,这样各个“任务”将由 List 管理:

var body: some View {
    VStack {
        Text(task.name)
        .font(.custom("Avenir Next Regular", size: 14))

var body: some View {
    Group {
        Text(task.name)
        .font(.custom("Avenir Next Regular", size: 14))

其次,将您的 TDTaskView 更改为 TaskView,这样您已经编写的代码将递归构建您的任务列表:

        if !task.subtasks.isEmpty {
            Section {
                ForEach(task.subtasks) {subtask in
                    TDTaskView(task: subtask)
                }
            }.padding(.leading)
        }

        if !task.subtasks.isEmpty {
            Section {
                ForEach(task.subtasks) {subtask in
                    TaskView(task: subtask)
                }
            }.padding(.leading)
        }

编辑

这是完整的工作代码(非常接近您的原始代码):

import SwiftUI

struct ContentView: View {
    var tasks: [Task] = [Task(name: "thing"), Task(name: "more work"), Task(name: "Huge job", isCompleted: false, subtasks: [Task(name: "smaller job"), Task(name: "sorta small job")])]
    
    var body: some View {
        List {
            ForEach(self.tasks) {task in
                TaskView(task: task)
            }
        }
    }
}

struct TaskView: View {
    @ObservedObject var task: Task
    
    var body: some View {
        Group {
            Text(task.name)
                .font(.custom("Avenir Next Regular", size: 14))
            
            //Here.................
            if !task.subtasks.isEmpty {
                Section {
                    ForEach(task.subtasks) {subtask in
                        TaskView(task: subtask)
                    }
                }.padding(.leading)
            }
        }
    }
}


class Task: Identifiable, ObservableObject {
    var id: UUID = UUID()
    var name: String
    @Published var isCompleted: Bool = false
    var subtasks = [Task]()
    
    init(name: String, isCompleted: Bool = false, subtasks: [Task] = [Task]()) {
        self.name = name
        self.isCompleted = isCompleted
        self.subtasks = subtasks
    }
}