buttonforeachswiftuistackzstack

How to put an element in front of a ForEach with a ZStack without making it overlapped


I am trying to create a layout in which there is a list of elements, and a button to add more elements in front of it. I know I could put it in the navigation bar, but that's not the graphic look I'd like to achieve. However, if I put those two elements inside a ZStack, the ForEach becomes overlapped, even though it's within a VStack. How can I solve this?

import SwiftUI

        struct ContentView: View {
        let arrayTest = ["Element 1", "Element 2", "Element 3"]
       
       var body: some View {
         NavigationView {
          ZStack {
            VStack {
                ForEach(arrayTest, id: \.self) { strings in
                    Text(strings)
                }
            }
           VStack {
           Spacer()
           HStack {
           Spacer()
            Button(action: {
              //AddView
              }) { 
                Image(systemName: "plus")
                  .background(Circle().foregroundColor(.yellow))
               }.padding(.trailing, 20)
               .padding(.bottom, 20)
             }
             }
           }
           }
          }
        }

Edit: To be more precise, I would like the button to be over the ForEach, because if I used a VStack and the list of elements was very long, the user would have to scroll all the way to the bottom to find the button. With a ZStack, it would always be visible no matter the point of the list the user is at.


Solution

  • Here is one way of using overlay, see example in code:

    struct ContentView: View {
        
        @State private var arrayTest: [String] = [String]()
        
        var body: some View {
            
            NavigationView {
                
                Form { ForEach(arrayTest, id: \.self) { strings in Text(strings) } }
                    .navigationTitle("Add Elements")
                
            }
            .overlay(
                
                Button(action: { addElement() })
                    { Image(systemName: "plus").font(Font.largeTitle).background(Circle().foregroundColor(.yellow)) }.padding()
                
                , alignment: .bottomTrailing)
            .onAppear() { for _ in 0...12 { addElement() } }
            
        }
        
        func addElement() { arrayTest.append("Element " + "\(arrayTest.count + 1)") }
        
    }
    

    enter image description here