带有动态变量的 ForEach 循环

ForEach loop with dynamic variable

我需要根据 @State bool 显示两个不同的图像,以便当用户按下图像时它显示第二个图像,当用户释放时它返回显示第一个图像。这一切都很完美,但是我有一种情况需要在 ForEach 循环中做同样的事情,因为我不相信 Swift 可以处理动态变量,所以我看不出如何做到这一点。

在下面的代码中,您将看到按钮的配置结构,然后在 MainView 的 ForEach 循环中调用它。 btnHover 变量需要在每次迭代时更改,否则所有按钮都会在按下单个按钮时显示悬停图像。

此外,我无法将其放入单独的结构中,然后在主视图中调用它。我今天花了很多时间沿着这条路走,似乎如果你从一个单独的结构调用 NavigationLink,你就不能再弹出到根目录。我不明白,但这显然是交易。所以,我需要在主视图中完成这项工作,而不是在单独的结构中。

实际代码要复杂得多(即每个按钮实际上是一个 NavigationLink),但我尽量将示例放在一起。

struct PressActions: ViewModifier {
    var onPress: () -> Void
    var onRelease: () -> Void

    func body(content: Content) -> some View {
        content
            .simultaneousGesture(
                DragGesture(minimumDistance: 0)
                    .onChanged({ _ in
                        onPress()
                    })
                    .onEnded({ _ in
                        onRelease()
                    })
            )
    }
}

extension View {
    func pressAction(onPress: @escaping (() -> Void), onRelease: @escaping (() -> Void)) -> some View {
        modifier(PressActions(onPress: {
            onPress()
        }, onRelease: {
            onRelease()
        }))
    }
}

struct DynamicBtn: View {
    var btnName: Bool
    var body: some View {
        Image(btnName == true ? "DynamicHover" : "Dynamic")
            .resizable()
            .aspectRatio(contentMode: .fit)
    }
}

struct MainView: View {
    @State private var btnHover: Bool = false
    let user = [Tim, John, Joe, Mary]
    var body: some View {
        ForEach(user, id: \.self) { user in
            VStack {
                DynamicBtn(btnName: btnHover)
                .pressAction {
                    btnHover = true
                } onRelease: {
                    btnHover = false
                }
            }
        }
    }
}

尝试类似这种方法,以便能够“按下”您的
DynamicBtn 并显示特定图像,然后释放“按下”以显示原始图像:

struct MainView: View {
    let users = [User(name: "Tim"), User(name: "John"), User(name: "Joe"), User(name: "Mary")]
    @State var selectedUser: User?  // <-- here
    
    var body: some View {
        ForEach(users, id: \.self) { user in
            DynamicBtn(btnName: selectedUser == user) // <-- here
                .pressAction {
                    selectedUser = user  // <-- here
                } onRelease: {
                    selectedUser = nil   // <-- here
                }
        }
    }
}

// for testing
struct User: Identifiable, Hashable {
    let id = UUID()
    var name = ""
}

注意:您可以在 DynamicBtn 中使用 Image(btnName ? "DynamicHover" : "Dynamic")