Mane Manero
Mane Manero

Reputation: 3798

SwiftUI: change ZStack .zIndex order

Goal is a menu where: User tap on green button: shows green menu User tap on blue button: shows blue menu

What I did: Set a state where "when tapped on green, green is top layer in ZStack).

Results: Didn't work: When tap on green, it goes to green. But then I tap on Blue and it stays green. The logic is definitely not correct

import SwiftUI

struct Menutest: View {

    @State private var showall = false
    @State private var showgreen = false
    @State private var showyellow = false
    @State private var showblue = false


    var body: some View {


        NavigationView {

           HStack {

            Spacer()

            ZStack {
                Rectangle()
                .foregroundColor(.blue)
                //.opacity(showblue ? 1 : 0)
               .zIndex(showblue ? 1 : 0)

                Rectangle()
                .foregroundColor(.green)
                 //.opacity(showgreen ? 1 : 0)
                .zIndex(showgreen ? 1 : 0)


                Rectangle()
                .foregroundColor(.yellow)
                 //.opacity(showyellow ? 1 : 0)
                .zIndex(showyellow ? 1 : 0)



            }
            .frame(width: 400.0)
          //  .offset(x: showall ? 0 : UIScreen.main.bounds.width)
            .animation(.easeInOut)

        }





        .navigationBarItems(



            trailing:

            HStack {


            Button(action: {
              //   self.showall.toggle()
                self.showyellow.toggle()
            })
            {
            Text("Yellow")

            }



           Button(action: {
            //     self.showall.toggle()
            self.showgreen.toggle()
            })
            {
            Text("Green")

            }


          Button(action: {
               //   self.showall.toggle()
                 self.showblue.toggle()
                })
                {
                Text("Blue")


               }



             }


            )

       }
      .navigationViewStyle(StackNavigationViewStyle())



    }
}




struct Menutest_Previews: PreviewProvider {
    static var previews: some View {
        Menutest()
        .colorScheme(.dark)
        .previewDevice("iPad Pro (12.9-inch) (3rd generation)")
    }
}

enter image description here

Question: How can I properly set a Zstack to show selected layers? Doesn't have to be using ZIndex, could be .hide() modifier, or some other logic.

Upvotes: 2

Views: 7037

Answers (2)

LuLuGaGa
LuLuGaGa

Reputation: 14428

In my opinion if you have a few Bool values of which only one can be true at any given time it is way easier to use an enum to represent the options - it is also significantly easier to manage the state. This has the behavior you expect:

struct Menutest: View {

    private enum Selection: String, CaseIterable {
        case blue = "Blue"
        case green = "Green"
        case yellow = "Yellow"

        static let allOptions = Array(Selection.allCases)

        func color() -> Color {
            switch self {
            case .blue:
                return .blue
            case .green:
                return .green
            case .yellow:
                return .yellow
            }
        }
    }

    @State private var showing: Selection? = nil

    var body: some View {
        NavigationView {
            HStack {
                Spacer()
                ZStack {
                    ForEach(Selection.allOptions, id: \.self) { selection in
                        Rectangle()
                            .foregroundColor(selection.color())
                            .zIndex(self.showing == selection ? 1 : 0)
                    }
                }   .frame(width: 400.0)
                    .animation(.easeInOut)
            }   .navigationBarItems(trailing:
                HStack {
                    ForEach(Selection.allOptions, id: \.self) { selection in
                        Button(action: { self.showing = selection }) {
                            Text(selection.rawValue)
                        }
                    }
                })
        }   .navigationViewStyle(StackNavigationViewStyle())
    }
}

Upvotes: 7

dot3
dot3

Reputation: 1226

You need to toggle the other BOOLs in addition to the BOOL from the button you are clicking.

The following works, although there may be a more elegant way to do it. replace the button section with:

Button(action: {
  self.showyellow = true
  self.showgreen = false
  self.showblue = false
 })
 {
  Text("Yellow")
}

Button(action: {
 self.showgreen = true
 self.showblue = false
 self.showyellow = false
})
{
 Text("Green")
}

Button(action: {
 self.showblue = true
 self.showyellow = false
 self.showgreen = false
})
{
 Text("Blue")
}
}

In a ZStack, the elements stack on top of each other. The first item is the lower-most layer, and the layers get stacked on top of each other.

In your version, when you click on Yellow, Blue and Green may still be stacked "above" the yellow layer, and thus you need to make sure to remove those other layers.

Upvotes: 4

Related Questions