You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI列表Section添加Header后Toolbar项重复问题求助

SwiftUI中Section添加Header后Toolbar操作项重复显示的解决方法

问题现象

用SwiftUI的List展示名称列表,将List包裹在Section中时功能正常,但为Section添加Header后,Toolbar里的操作项会重复显示;注释掉Header相关代码后,Toolbar恢复正常表现:

  • 正常状态:仅显示1个「Delete Name」(左侧)和1个「Add Name」(右侧)
  • 异常状态:Toolbar操作项重复出现

问题根源

你的视图结构错误地将List嵌套在Section外部——Section本质是List的子组件,用于分组列表内的内容,而非用来包裹整个List。当把Section作为根视图并添加header时,会导致SwiftUI视图层级混乱,进而触发Toolbar元素的重复渲染。

解决方案

调整视图结构,将Section放到List内部,或者直接给List设置头部标题,以下是两种可行方案:

方案1:将Section移至List内部(推荐)

把Section作为List的子元素,用来分组列表内容,同时给Section设置header:

var body: some View {
    List {
        Section(header: {
            Text("Names in Order")
                .frame(maxWidth: .infinity, alignment: .leading) // 用maxWidth替代固定值,适配不同屏幕
        }) {
            ForEach(entrants) { entrant in
                EntrantCell(entrant: entrant)
                    .onTapGesture {
                        entrantToEdit = entrant
                    }
            }
            .onDelete { indexSet in
                for index in indexSet {
                    context.delete(entrants[index])
                    try! context.save()
                }
            }
        }
    }
    // 后续overlay、toolbar等代码保持不变
}

方案2:直接给List添加头部标题

如果不需要Section的分组样式,只是想给List加标题,可以直接使用List的listHeader修饰符:

var body: some View {
    List {
        ForEach(entrants) { entrant in
            EntrantCell(entrant: entrant)
                .onTapGesture {
                    entrantToEdit = entrant
                }
        }
        .onDelete { indexSet in
            for index in indexSet {
                context.delete(entrants[index])
                try! context.save()
            }
        }
    }
    .listHeader {
        Text("Names in Order")
            .frame(maxWidth: .infinity, alignment: .leading)
    }
    // 后续代码保持不变
}

修改后的完整代码

import SwiftUI
import SwiftData

enum AppearanceStyle {
    case dark
    case light
    case auto
}

struct EntrantsHomeView: View {
    @Environment(\.modelContext) var context
    @State private var isShowingItemSheet = false
    @Query(sort: \EntrantsDatabase.number) var entrants: [EntrantsDatabase]
    @State private var entrantToEdit: EntrantsDatabase?
    @State private var appearance: AppearanceStyle = .auto
    
    var body: some View {
        List {
            Section(header: {
                Text("Names in Order")
                    .frame(maxWidth: .infinity, alignment: .leading)
            }) {
                ForEach(entrants) { entrant in
                    EntrantCell(entrant: entrant)
                        .onTapGesture {
                            entrantToEdit = entrant
                        }
                }
                .onDelete { indexSet in
                    for index in indexSet {
                        context.delete(entrants[index])
                        try! context.save()
                    }
                }
            }
        }
        .overlay {
            if entrants.isEmpty {
                ContentUnavailableView(label: {
                    Label("No Names", systemImage: "list.bullet.rectangle.portrait")
                }, description: {
                    Text("Start adding names to your list.")
                }, actions: {
                    Button("Add Name") {isShowingItemSheet = true }
                })
                .offset(y: -60)
            }
        }
        .toolbar(content: {
            if !entrants.isEmpty {
                ToolbarItem(placement: .topBarLeading) {
                    Button("Delete Name", systemImage: "minus") {
                        do {
                            try context.delete(model: EntrantsDatabase.self)
                        } catch {
                            print("Failed to clear the Names database")
                        }
                    }
                }
                ToolbarItem(placement: .topBarTrailing) {
                    Button("Add Name", systemImage: "plus") {
                        isShowingItemSheet = true
                    }
                }
            }
        })
        .navigationTitle("Names' Manager")
        .navigationBarTitleDisplayMode(.large)
        .sheet(isPresented: $isShowingItemSheet) {AddEntrantSheet() }
        .sheet(item: $entrantToEdit) { entrant in
            UpdateEntrantSheet(entrant: entrant)
        }
    }
}

struct EntrantCell: View {
    let entrant: EntrantsDatabase
    var body: some View {
        HStack {
            CircledText(text: String(entrant.number))
            Spacer()
            Text(entrant.name)
                .frame(width: 160, alignment: .leading)
                .bold()
            Spacer()
        }
    }
}

内容的提问来源于stack exchange,提问作者Edward Hasted

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 01:11:13