当单击 SwiftUI 中的列表项按钮时,我们如何更改按钮的文本?

How we can change text of button when a button is clicked for list items in SwiftUI?

我在 SwiftUI 中有列表视图,当我使用上下文菜单时,我想将项目的星形图标作为收藏夹或取消收藏夹,当我单击文本按钮时,它会显示收藏夹文本,但是当我点击另一个项目它显示不喜欢的文本,我不知道如何解决它,有想法吗?

最喜欢的模特:

import SwiftUI

struct FavoriteModel{
    var isFavorite: Bool = false
    var timeStamp: Date = Date()
    var userIds: Set<UUID> = []
    mutating func toogleFavorite(userId: UUID){
        isFavorite.toggle()
        timeStamp = Date()
        
        if isFavorite{
            userIds.insert(userId)
        }else{
            userIds.remove(userId)
        }
    }
}

型号:

struct Restaurant: Identifiable {
    var id = UUID()
    var name: String
    var image: String
    var isFavorite: Bool = false
  
}

基本图像行:

struct BasicImageRow: View {

    var restaurant: Restaurant
    
    var body: some View {
        HStack {
            Image(restaurant.image)
                .resizable()
                .frame(width: 40, height: 40)
                .cornerRadius(5)
            Text(restaurant.name)
          
            if restaurant.isFavorite {
                Spacer()
                
                Image(systemName: "star.fill")
                    .foregroundColor(.yellow)
            }
        }
    }
}

查看:

import SwiftUI

struct ContentView: View {
    
    @State var showAnswer = false
    @State var toggleText = false

    @State private var selectedRestaurant: Restaurant?
    
  @State private  var restaurants = [ Restaurant(name: "Cafe Deadend", image: "cafedeadend"),
                  Restaurant(name: "Homei", image: "homei"),
                  Restaurant(name: "Teakha", image: "teakha"),
                  Restaurant(name: "Cafe Loisl", image: "cafeloisl"),
                  Restaurant(name: "Petite Oyster", image: "petiteoyster"),
                  Restaurant(name: "For Kee Restaurant", image: "forkeerestaurant"),

            ]

 
    var body: some View {
        List {
            ForEach(restaurants) { restaurant in
                BasicImageRow(restaurant: restaurant)
                    .contextMenu {
                        
                        Button(action: {
                           self.showAnswer = true
                             self.toggleText.toggle()
                            self.setFavorite(item: restaurant)
                        }) {
                            HStack {
                               Text(toggleText ? "Favorite" : "UnFavorite")
    
                               Text(toggleText ? "UnFavorite" : "Favorite")

                                Image(systemName: "star")
                            }
                        }
                    }
                    .onTapGesture {
                        self.selectedRestaurant = restaurant
                    }
                    .actionSheet(item: self.$selectedRestaurant) { restaurant in
                        
                        ActionSheet(title: Text("What do you want to do"), message: nil, buttons: [
                            
                            .default(Text("Mark as Favorite"), action: {
                                self.setFavorite(item: restaurant)
                            }),
                            
                           
                            .cancel()
                        ])
                    }
            }
           
        }
    }
   
    
    private func setFavorite(item restaurant: Restaurant) {
        if let index = self.restaurants.firstIndex(where: { [=13=].id == restaurant.id }) {
            self.restaurants[index].isFavorite.toggle()
        }
    }
   
}

如果我对问题的理解正确,请通过删除所有 toggleText 并使用@Ali Momeni 建议尝试此方法:

struct ContentView: View {
    @State var showAnswer = false
    
    @State private var selectedRestaurant: Restaurant?
    
    @State private var restaurants = [ Restaurant(name: "Cafe Deadend", image: "cafedeadend"),
                                       Restaurant(name: "Homei", image: "homei"),
                                       Restaurant(name: "Teakha", image: "teakha"),
                                       Restaurant(name: "Cafe Loisl", image: "cafeloisl"),
                                       Restaurant(name: "Petite Oyster", image: "petiteoyster"),
                                       Restaurant(name: "For Kee Restaurant", image: "forkeerestaurant")
    ]
    
    private func RestaurantRow(restaurant: Restaurant) -> some View {
        BasicImageRow(restaurant: restaurant)
            .contextMenu {
                Button(action: {
                    showAnswer = true
                    setFavorite(item: restaurant)
                }) {
                    HStack {
                        Text(restaurant.isFavorite ? "UnFavorite" : "Favorite")
                        Image(systemName: "star")
                    }
                }
            }.id(restaurant.id)
            .onTapGesture {
                selectedRestaurant = restaurant
            }
            .actionSheet(item: $selectedRestaurant) { restaurant in
                ActionSheet(title: Text("What do you want to do"),
                            message: nil,
                            buttons: [
                                .default(
                                    Text(restaurant.isFavorite ? "Mark as UnFavorite" : "Mark as  Favorite"),
                                    action: {
                                        setFavorite(item: restaurant)
                                    }),
                                .cancel()
                            ])
            }
    }
    
    var body: some View {
        List {
            ForEach(restaurants) { restaurant in
                if restaurant.isFavorite {
                    RestaurantRow(restaurant: restaurant)
                } else {
                    RestaurantRow(restaurant: restaurant)
                }
            }
        }
    }
    
    private func setFavorite(item restaurant: Restaurant) {
        if let index = restaurants.firstIndex(where: { [=10=].id == restaurant.id }) {
            restaurants[index].isFavorite.toggle()
        }
    }
    
}

我建议将模型更改为 Apple's Fruta sample 实现收藏夹的方式。例如

class Model: ObservableObject {
    ...

    @Published var favoriteSmoothieIDs = Set<Smoothie.ID>()

    func toggleFavorite(smoothieID: Smoothie.ID) {
        if favoriteSmoothieIDs.contains(smoothieID) {
            favoriteSmoothieIDs.remove(smoothieID)
        } else {
            favoriteSmoothieIDs.insert(smoothieID)
        }
    }

    func isFavorite(smoothie: Smoothie) -> Bool {
        favoriteSmoothieIDs.contains(smoothie.id)
    }

    ...
}

struct SmoothieFavoriteButton: View {
    @EnvironmentObject private var model: Model
    
    var isFavorite: Bool {
        guard let smoothieID = model.selectedSmoothieID else { return false }
        return model.favoriteSmoothieIDs.contains(smoothieID)
    }
    
    var body: some View {
        Button(action: toggleFavorite) {
            if isFavorite {
                Label {
                    Text("Remove from Favorites", comment: "Toolbar button/menu item to remove a smoothie from favorites")
                } icon: {
                    Image(systemName: "heart.fill")
                }
            } else {
                Label {
                    Text("Add to Favorites", comment: "Toolbar button/menu item to add a smoothie to favorites")
                } icon: {
                    Image(systemName: "heart")
                }

            }
        }
        .disabled(model.selectedSmoothieID == nil)
    }
    
    func toggleFavorite() {
        guard let smoothieID = model.selectedSmoothieID else { return }
        model.toggleFavorite(smoothieID: smoothieID)
    }
}

struct SmoothieFavoriteButton_Previews: PreviewProvider {
    static var previews: some View {
        SmoothieFavoriteButton()
            .padding()
            .previewLayout(.sizeThatFits)
            .environmentObject(Model())
    }
}

如您所见,将结构用于模型数据确实需要一些 re-thinking。