I have a view that generates multiple rows in a list. Each row - I append a button that creates a pop out of sorts over the row. My issue is since the button is being generated separately on each row, when I toggle another button on a different row, the previous button I opened remains open until I click it again.
Is there a way I can have the rows communicate with each other so if another button is clicked, the button previously clicked disappears?
struct RecipeFullListRow: View {
var body: some View {
ZStack{
Text("Cheese Omelette")
.font(.body)
Text("10g 25g 88g")
.foregroundColor(.gray)
.padding(.top, 80)
.padding(.bottom, 10)
.padding(.trailing, 10)
.frame(height:90)
if showRecipeOptions{
ReditorPopUp(shown: $showRecipeOptions)
.padding(.top, 20)
.padding(.leading, 15)
}
}
.padding(.top, -10)
.padding(5)
Button(action: {
}){
Image(systemName: "slider.horizontal.3")
.padding(.top, 10)
.foregroundColor(.black)
.onTapGesture{
showRecipeOptions.toggle()
}
}
.buttonStyle(BorderlessButtonStyle())
}
}
**BUTTON ATTACHED TO EACH ROW
struct ReditorPopUp: View {
@Binding var shown: Bool
@State var showEditRecipe = false
var body: some View {
if shown{
ZStack{
VStack (alignment: .leading, spacing: 20){
HStack(spacing:12){
Image(systemName: "pencil")
.font(.title2)
Button(action:{
showEditRecipe.toggle()
}){
Text("Edit")
.foregroundColor(.black)
} .buttonStyle(BorderlessButtonStyle())
//present editor
.fullScreenCover(isPresented: $showEditRecipe){
RecipeEditor()
}
}
HStack(spacing: 12){
Image(systemName: "trash")
.font(.title2)
.foregroundColor(.red)
Button(action: {
}){
Text("Delete")
.foregroundColor(.black)
} .buttonStyle(BorderlessButtonStyle())
}
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.white)
///art of animation
.transition(.backslide)
.animation(.easeInOut(duration: 0.25))
}
}
}
struct RecipeFullListView: View {
@Environment(\.dismiss) var dismiss
@State var listofRecipes: [RecipeListModel] = RecipeList.recipes
@State private var active = false
init(){
UITableView.appearance().backgroundColor = .clear
}
var body: some View {
let withIndex = listofRecipes.enumerated().map({ $0 })
ZStack{
VStack{
Text("Recipes")
//.padding(.bottom, -20)
//.padding(.top, 40)
.font(.title2)
List{
ForEach(withIndex, id: \.element.name){ index, recipe in
RecipeFullListRow(recipe: recipe, recipeName: recipe.name, index: index)
}
}
}//end of VStack
}
}
}
I have also attached a gif of the issue below
CodePudding user response:
Instead of Bool make it index
or row item
type, so when button clicked instead of toggle
assign current row/item, this will close previous automatically before show current. Of course you need to inject into the view index/item from ForEach level.
1)
if showRecipeOptions == index { // index of current row, ...
// if showRecipeOptions == item { // or item of current row
ReditorPopUp(shown: $showRecipeOptions)
.padding(.top, 20)
.padding(.leading, 15)
}
-
Button(action:{ showEditRecipe = index // index of tapped row
// showEditRecipe = index // or item of tapped row
}){
CodePudding user response:
In your data model (ObservableObject
) holding data for each row, you could add a variable holding the index of the row being selected for editing with @Published
wrapper. Changing it would redraw the list with the edit view for new row.