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

Swift中如何在ForEach循环里仅显示数组内指定的两个元素?

解决方案:在PlayingCreatures视图中仅展示两个生物元素

根据你的需求,这里提供几种实用实现方式,可根据展示逻辑选择:

方式一:固定展示数组前两个元素

直接对data.creatures做切片操作,取前2个元素传入ForEach即可:

struct PlayingCreatures: View {
    
    @EnvironmentObject var data : CreatureZoo
    
    var body: some View {
        VStack {
            ZStack {
                // 取数组前2个元素
                ForEach(data.creatures.prefix(2)) { creature in
                    Text(creature.emoji)
                        .resizableFont()
                        .offset(creature.offset)
                        .rotationEffect(creature.rotation)
                        .animation(.spring(response: 0.5, dampingFraction: 0.5), value: creature.rotation)
                        .animation(.default.delay(data.indexFor(creature) / 10), value: creature.offset)
                }
            }
            .onTapGesture {
                data.randomizeOffsets()
            }
        }
    }
}

方式二:随机展示两个不同元素

如果需要每次打开视图或点击时切换展示的生物,可按以下两种方式实现:

方案A:在视图内直接处理

通过计算属性生成随机子数组,配合状态变量触发刷新:

struct PlayingCreatures: View {
    
    @EnvironmentObject var data : CreatureZoo
    @State private var refreshTrigger = false
    
    // 生成随机两个生物的计算属性
    var randomTwoCreatures: [Creature] {
        guard data.creatures.count >= 2 else { return data.creatures }
        let _ = refreshTrigger // 依赖状态变量,触发重新计算
        return Array(data.creatures.shuffled().prefix(2))
    }
    
    var body: some View {
        VStack {
            ZStack {
                ForEach(randomTwoCreatures) { creature in
                    Text(creature.emoji)
                        .resizableFont()
                        .offset(creature.offset)
                        .rotationEffect(creature.rotation)
                        .animation(.spring(response: 0.5, dampingFraction: 0.5), value: creature.rotation)
                        .animation(.default.delay(data.indexFor(creature) / 10), value: creature.offset)
                }
            }
            .onTapGesture {
                data.randomizeOffsets()
                refreshTrigger.toggle() // 点击时切换随机生物
            }
        }
    }
}

方案B:在CreatureZoo中封装方法(符合MVVM架构)

先在CreatureZoo扩展中添加生成随机子数组的方法:

extension CreatureZoo {
    // 新增:获取随机两个生物
    func randomTwoCreatures() -> [Creature] {
        guard creatures.count >= 2 else { return creatures }
        return Array(creatures.shuffled().prefix(2))
    }
    
    // 原有方法保留
    func randomizeOffsets() {
        for index in creatures.indices {
            creatures[index].offset = CGSize(width: CGFloat.random(in: -200...200), height: CGFloat.random(in: -200...200))
            creatures[index].rotation = Angle(degrees: Double.random(in: 0...720))
        }
    }
    
    func synchronizeOffsets() {
        let randomOffset = CGSize(width: CGFloat.random(in: -200...200), height: CGFloat.random(in: -200...200))
        for index in creatures.indices {
            creatures[index].offset = randomOffset
        }
    }
    
    func indexFor(_ creature: Creature) ->  Double {
        if let index = creatures.firstIndex(where: { $0.id == creature.id }) {
            return Double(index)
        }
        return 0.0
    }
}

再在视图中调用该方法:

struct PlayingCreatures: View {
    
    @EnvironmentObject var data : CreatureZoo
    @State private var refreshTrigger = false
    
    var body: some View {
        VStack {
            ZStack {
                ForEach(data.randomTwoCreatures()) { creature in
                    Text(creature.emoji)
                        .resizableFont()
                        .offset(creature.offset)
                        .rotationEffect(creature.rotation)
                        .animation(.spring(response: 0.5, dampingFraction: 0.5), value: creature.rotation)
                        .animation(.default.delay(data.indexFor(creature) / 10), value: creature.offset)
                }
            }
            .onTapGesture {
                data.randomizeOffsets()
                refreshTrigger.toggle()
            }
        }
        .id(refreshTrigger) // 通过id触发视图刷新,重新获取随机生物
    }
}

注意事项

  • 由于Creature遵循Identifiable协议,切片或子数组可直接传入ForEach,无需额外指定ID。
  • 所有方案都处理了数组元素不足2个的情况,避免崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 14:29:10