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

SwiftUI嵌套List无法滚动及.onDelete触发失败问题求助

问题解决:SwiftUI列表无法滚动、滑动删除失效

问题分析

你的代码存在两个核心问题导致列表交互失效:

  1. ListInsideScontrino的视图层级错误,末尾直接添加的Color视图会干扰List的触摸事件传递
  2. 承载视图ScontrinoView中,List未获得足够布局空间,加上自定义mask的影响,导致滚动和滑动删除的触摸区域被限制

解决方案

1. 修复ListInsideScontrino的视图结构

将背景色放到ZStack底层,避免额外视图覆盖List的交互区域:

import SwiftUI

struct ListInsideScontrino: View {
    
    @State private var isAddFoodViewPresented = false
    @EnvironmentObject var foodData: FoodData
    
    var foodItems: [MyFoodItem] {
        foodData.foodItems
    }
    
    var body: some View {
        ZStack {
            // 背景色放在ZStack底层,不干扰上层List交互
            Color.gray.opacity(0.100)
            
            if foodItems.isEmpty {
                VStack {
                    Text("你的订单汇总将在添加菜品后显示在这里。")
                        .font(.callout)
                        .foregroundColor(.gray)
                        .multilineTextAlignment(.center)
                        .padding()
                    
                    Text("点击右下角按钮开始添加食物!")
                        .font(.callout)
                        .foregroundColor(.gray)
                }
                .padding()
            } else {
                List {
                    ForEach(foodData.foodItems) { foodItem in
                        FoodItemRow(foodItem: foodItem)
                            .listRowSeparator(.hidden)
                    }
                    .onDelete(perform: deleteFoodItem)
                }
                .listStyle(InsetGroupedListStyle())
                // 移除List自带背景,使用ZStack统一背景
                .scrollContentBackground(.hidden)
            }
        }
    }
    
    private func deleteFoodItem(at offsets: IndexSet) {
        foodData.foodItems.remove(atOffsets: offsets)
    }
}

#Preview {
    ListInsideScontrino()
        .environmentObject(FoodData()) // 预览时注入环境对象
}

2. 调整ScontrinoView的布局与mask

给List设置完整可用空间,同时优化mask路径计算(避免直接依赖UIScreen尺寸):

import SwiftUI

struct ScontrinoView: View {
    var body: some View {
        ZStack {
            ListInsideScontrino()
                .frame(maxWidth: .infinity, maxHeight: .infinity) // 让List占满可用空间
        }
        .padding()
        .mask(
            GeometryReader { geo in
                Path { path in
                    path.move(to: CGPoint(x: 0, y: 0))
                    
                    let rowCount = Int(geo.size.height / 20)
                    for i in 0..<rowCount {
                        let x = CGFloat(i) * 20
                        path.addLine(to: CGPoint(x: x + 10, y: 30))
                        path.addLine(to: CGPoint(x: x + 20, y: 20))
                    }
                    
                    path.addLine(to: CGPoint(x: geo.size.width, y: geo.size.height))
                    path.addLine(to: CGPoint(x: 0, y: geo.size.height))
                }
                .scaleEffect(CGSize(width: 1.0, height: -1.0))
            }
        )
        .shadow(radius: 5)
        .cornerRadius(15)
        .ignoresSafeArea()
    }
}

3. 确保数据模型的响应式

确认FoodData中的foodItems使用@Published修饰,保证List能正确响应数据变化:

class FoodData: ObservableObject {
    @Published var foodItems: [MyFoodItem] = []
}

关键修改说明

  • 把背景色移到ZStack底层,避免额外视图拦截List的触摸事件
  • 给List添加scrollContentBackground(.hidden),统一使用ZStack的背景色,避免List自带背景干扰
  • 用GeometryReader替代UIScreen.main.bounds计算mask路径,适配不同设备和布局
  • 给List设置frame(maxWidth: .infinity, maxHeight: .infinity),确保它获得足够的滚动空间

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 02:57:14