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

SwiftUI开发Mac仿iOS电池小组件运行后显示空白窗口,求问题排查

问题排查与修复方案

核心问题

  • 初始化的PublishedDevices实例deviceArrays始终为空,你从未将传入的devices数组拆分后赋值给它,ForEach遍历空数组自然无内容渲染,是空白页的直接原因
  • 用单状态变量currentDevice绑定所有Progresso的device参数,会导致所有卡片只能显示同一个设备的信息,逻辑错误
  • 仅计算了devicesPerRow、rows参数,没有实际用来拆分设备数组生成对应的行数据,计算逻辑完全无效
  • GeometryReader默认撑满父容器,但内部内容无明确高度约束,外层ScrollView无法正确计算内容高度,也会导致内容无法正常显示

修复后的BatteryGrid.swift代码

struct BatteryGrid: View {
    @Binding var devices: [Device]
    @Binding var size: Double
    @ObservedObject var deviceArrays = PublishedDevices()
    @State var devicesPerRow = 0

    var body: some View {
        VStack(spacing: 20) {
            // 只用来获取父容器宽度,不占实际显示空间
            GeometryReader { geometry in
                Color.clear
                    .onAppear {
                        devicesPerRow = Int(geometry.size.width) / Int(size)
                        splitDevicesToRows()
                    }
            }
            .frame(height: 0)
            
            // 生成每一行
            ForEach(deviceArrays.devices, id: \.id) { deviceArray in
                HStack(spacing: 10) {
                    // 生成当前行的所有设备卡片
                    ForEach(deviceArray.row, id: \.id) { device in
                        Progresso(device: .constant(device), size: $size)
                            .frame(width: size)
                    }
                    // 不足一行的位置补空白占位,保证布局对齐
                    ForEach(0..<(devicesPerRow - deviceArray.row.count), id: \.self) { _ in
                        Spacer()
                            .frame(width: size)
                    }
                }
            }
        }
        .padding()
    }

    /// 将一维设备数组拆分为多行
    private func splitDevicesToRows() {
        guard devicesPerRow > 0 else { return }
        var tempRows: [DeviceRow] = []
        var currentRow: [Device] = []
        for device in devices {
            currentRow.append(device)
            if currentRow.count == devicesPerRow {
                tempRows.append(DeviceRow(row: currentRow))
                currentRow.removeAll()
            }
        }
        if !currentRow.isEmpty {
            tempRows.append(DeviceRow(row: currentRow))
        }
        deviceArrays.devices = tempRows
    }
}

struct DeviceRow: Identifiable {
    var row: [Device] = []
    var id = UUID()
}
class PublishedDevices: ObservableObject {
    @Published var devices: [DeviceRow] = []
}

额外注意事项

  • 确认Device结构体遵循Identifiable协议,存在唯一的id属性,否则ForEach遍历会崩溃
  • 确认Device的icon()方法已正确实现,返回对应设备类型的Image实例
  • 如果需要支持设备列表动态更新,可以新增onChange(of: devices) modifier,监听到设备列表变化时重新调用splitDevicesToRows()更新布局

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 01:00:05