首页 > 解决方案 > 父母可以知道其子 ForEach 的当前迭代吗

问题描述

有没有办法让 ForEach 的容器知道它的当前迭代。我已经考虑了一段时间,我所能想到的就是让每个项目都是一个按钮,当点击它时会改变一些状态..但这是唯一的方法吗?

我担心这可能是一个复杂的解决方案

[视频缩略图

import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            Text("Parent View")
                .font(.largeTitle)
            Text("Is there a way for the parent view to know which object in child ForEach to know what item is on screen?").bold()
                .padding()
                .padding(.horizontal)
            Spacer()
            ScrollView(.horizontal) {
                HStack {
                    ForEach(0..<10) { object in
                        ZStack {
                            Text(object.description)
                                .font(.custom("", size: 50))
                            Circle()
                            .stroke()
                            .frame(width: 370)
                                .padding()
                        }
                        
                    }.padding()
                }
            }
            Text("Currently showing   ??  ")
            Text("How to increment this number with current item in view")
                .padding()
            
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

标签: swiftui

解决方案


一种可能的解决方案是读取容器和滚动的项目视图框架并根据交集分数更新计数器状态。

这是一个演示。使用 Xcode 12.4 / iOS 14.4 准备

演示

struct ContentView: View {
    @State private var current = 0

    @ViewBuilder
    var header: some View {    // to simplify body
        Text("Parent View")
            .font(.largeTitle)
        Text("Is there a way for the parent view to know which object in child ForEach to know what item is on screen?").bold()
            .padding()
            .padding(.horizontal)
    }

    @ViewBuilder
    var footer: some View {    // to simplify body
        Text("Currently showing \(current)  ")
        Text("How to increment this number with current item in view")
            .padding()
    }

    var body: some View {
        GeometryReader { gp in
            VStack {
                header
                Spacer()

                ScrollView(.horizontal) {
                    HStack(spacing: 0) {
                        ForEach(0..<10) { object in
                            ZStack {
                                Text(object.description)
                                    .font(.custom("", size: 50))
                                Circle().stroke()
                                    .padding()
                            }
                            .frame(width: gp.size.width)
                            .background(GeometryReader { sp -> Color in
                                let bounds = sp.frame(in: .global)
                                let frame = gp.frame(in: .global)

                                // tune factor as you need
                                if frame.intersection(bounds).size.width > frame.size.width * 0.55 {
                                    DispatchQueue.main.async {
                                        current = object
                                    }
                                }
                                return Color.clear
                            })
                        }
                    }
                }

                footer
            }
        }
    }
}

推荐阅读