I have the following View structure and run into the problem of the button working the first time I click and disabling the button like it should, but once I clicked one button it does not work for the other buttons. The Item is always the right one, I checked that by printing it out.
My ReelsView
:
struct ReelsView: View {
@State var currentReel = ""
@State var items: [Item] = [
Item(chance: "1:1m", tradeIn: 2000, name: "Apple Watch", price: "$200", rarityType: "common", description: "The Apple Watch", reel: Reel(player: AVPlayer(url: URL(fileURLWithPath: Bundle.main.path(forResource: "apple-watch", ofType: "mp4") ?? "")), bid: false)),
Item(chance: "1:20m", tradeIn: 27500, name: "Ibiza vacation", price: "$2750,00", rarityType: "superRare", description: "Such a wonderful place for a vacation", reel: Reel(player: AVPlayer(url: URL(fileURLWithPath: Bundle.main.path(forResource: "ibiza", ofType: "mp4") ?? "")), bid: false)),
]
var body: some View {
TabView(selection: $currentReel) {
ForEach($items) { $reel in
ReelsPlayer(reel: $reel.reel, currentReel: $currentReel, item: $reel)
.tag(reel.reel.id)
}
}
}
}
My ReelsPlayer
:
struct ReelsPlayer: View {
@Binding var reel: Reel
@Binding var currentReel: String
@Binding var item: Item
var body: some View {
ZStack {
if let player = reel.player {
CustomVideoPlayer(player: player)
.allowsHitTesting(false)
}
}
.overlay {
BottomOverlay(item: $item)
.allowsHitTesting(true)
}
}
}
My BottomOverlay
:
struct BottomOverlay: View {
@Binding var item: Item
var body: some View {
Button() {
item.reel.bid.toggle()
print("item: ", item)
print("item: ", $item)
} label: {
Text(item.reel.bid ? "Already Bid" : "Bid")
}
}
}
struct Reel: Identifiable {
var id = UUID().uuidString
var player: AVPlayer
var bid: Bool
}
struct Item: Identifiable, Hashable {
static func == (lhs: Item, rhs: Item) -> Bool {
lhs.id == rhs.id
}
func hash(into hasher: inout Hasher) {
hasher.combine(chance)
hasher.combine(name)
hasher.combine(price)
hasher.combine(tradeIn)
hasher.combine(rarityType)
hasher.combine(description)
}
var id: String = UUID().uuidString
var chance: String
var tradeIn: Int
var name: String
var price: String
var rarityType: String
var description: String
var reel: Reel
}
CodePudding user response:
Here is the code I used in my test, to show that the two buttons acts separately. Click on one, and it print the item id and state. Click on the other, and same for that item. If you un-comment .disabled(item.clicked)
, then it only works once, because the Button (for that item) is now disabled.
struct Item: Identifiable {
let id = UUID()
var name: String
var clicked: Bool
}
struct ContentView: View {
var body: some View {
MainView()
}
}
struct MainView: View {
@State var items: [Item] = [Item(name: "item1", clicked: false),Item(name: "item2", clicked: false)]
var body: some View {
ForEach($items) { $item in
ItemView(item: $item)
}
}
}
struct ItemView: View {
@Binding var item: Item
var body: some View {
VStack {
Color.green
}.overlay {
OverlayView(item: $item)
}
}
}
struct OverlayView: View {
@Binding var item: Item
var body: some View {
VStack (spacing: 33){
Button() {
item.clicked.toggle()
print("--> item.id: \(item) item.clicked: \(item.clicked)")
} label: {
Text(item.name)
}//.disabled(item.clicked)
// Button() {
// item.clicked.toggle()
// } label: {
// Text("enable again")
// }
}
}
}
EDIT-1: in view of your new code. Try this example code, works well for me
import Foundation
import SwiftUI
import UIKit
import AVFoundation
import AVKit
struct ContentView: View {
var body: some View {
ReelsView()
}
}
struct ReelsView: View {
@State var currentReel = ""
@State var items: [Item] = [
Item(chance: "1:1m", tradeIn: 2000, name: "Apple Watch", price: "$200", rarityType: "common", description: "The Apple Watch", reel: Reel(player: AVPlayer(url: URL(fileURLWithPath: Bundle.main.path(forResource: "apple-watch", ofType: "mp4") ?? "")), bid: false)),
Item(chance: "1:20m", tradeIn: 27500, name: "Ibiza vacation", price: "$2750,00", rarityType: "superRare", description: "Such a wonderful place for a vacation", reel: Reel(player: AVPlayer(url: URL(fileURLWithPath: Bundle.main.path(forResource: "ibiza", ofType: "mp4") ?? "")), bid: false)),
]
var body: some View {
TabView(selection: $currentReel) {
ForEach($items) { $item in
ReelsPlayer(currentReel: $currentReel, item: $item) // <-- here
.tag(item.reel.id)
}
}.tabViewStyle(.page) // <-- here
}
}
struct ReelsPlayer: View {
@Binding var currentReel: String
@Binding var item: Item // <-- here
var body: some View {
ZStack {
if let player = item.reel.player { // <-- here
// CustomVideoPlayer(player: player)
// for testing
VStack {
if item.name == "Apple Watch" { Color.yellow } else { Color.green }
}
.allowsHitTesting(false)
}
}
.overlay {
BottomOverlay(item: $item)
.allowsHitTesting(true)
}
}
}
struct BottomOverlay: View {
@Binding var item: Item
var body: some View {
Button() {
item.reel.bid.toggle()
print("----> BottomOverlay item.reel.bid: ", item.reel.bid) // <-- here
} label: {
Text(item.reel.bid ? "Already Bid" : "Bid")
}
}
}
struct Reel: Identifiable, Hashable { // <-- here
var id = UUID().uuidString
var player: AVPlayer
var bid: Bool
}
struct Item: Identifiable, Hashable { // <-- here
var id: String = UUID().uuidString
var chance: String
var tradeIn: Int
var name: String
var price: String
var rarityType: String
var description: String
var reel: Reel
}