带有动态变量的 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")
。
我需要根据 @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")
。