skip to Main Content

When using TabView, the "AddItemView" shows itself as multiple buttons, but should just be one button. Each button takes the user to a different piece of the view. For example, one button shows the title, another button shows a list etc.

The TabView code:

struct MainTabView: View {
var body: some View {
    TabView {
        
        ContentView()
            .tabItem {
                Label("Recipes", systemImage: "list.dash")
            }

        AddItemView(imageToUpload: Data.init(), recipeStep: [String].init(), stepNumber: [Int].init())
            .tabItem {
                Label("Add", systemImage: "plus")
            }
        
        SettingsView()
            .tabItem {
                Label("Settings", systemImage: "gearshape.2")
            }

    }
}
}

What is actually displayed:

enter image description here

As you can see, the "Add" is repeated multiple times.

Any thoughts on what could be causing this?

EDIT — AddItemView code

struct AddItemView: View {

@StateObject var viewModel = ViewModel()
@State var imageToUpload: Data
@StateObject var vm = CoreDataRelationshipViewModel()
@Environment(.presentationMode) var presentationMode
@State var recipeStep: [String]
@State var stepInfo: String = ""
@State var textFieldCount: Int = 1
@State var stepNumber: [Int]
@State var recipeName: String = ""
@State var errorText = ""
@State var stepErrorColor = Color.white.opacity(0)
@State var nameErrorColor = Color.white.opacity(0)
@State var recipesToBind = [StepsEntity].init()
@State var showImage = true
@StateObject var pubRecArray = PublishedRecipeStepAddItemView()
@State private var showingAlert = false

var body: some View {
    ZStack {
        HStack {
            Spacer()
            Button(action: {
                showingAlert = true
            }) {
                Image(systemName: viewModel.buttonImage)
            }
            .alert(isPresented: $showingAlert) { () -> Alert in
                Alert(title: Text("Upload Image"), primaryButton: .default(Text("Choose Photo"), action: {
                    viewModel.choosePhoto()
                }), secondaryButton: .default(Text("Take Photo"), action: {
                    viewModel.takePhoto()
                }))
            }
            //placing the imageview directly in the image section of the button allows for both the camera icon and the uploaded image to be a button
            Button(action: {
                showingAlert = true
            }) {
                imageView(for: viewModel.selectedImage)
                    .frame(width: viewModel.frameDimensionsPublished, height: viewModel.frameDimensionsPublished, alignment: .trailing)
                    .cornerRadius(10)
            }
            .alert(isPresented: $showingAlert) { () -> Alert in
                Alert(title: Text("Upload Image"), primaryButton: .default(Text("Choose Image"), action: {
                    viewModel.choosePhoto()
                }), secondaryButton: .default(Text("Take Photo"), action: {
                    viewModel.takePhoto()
                }))
            }
            .buttonStyle(PlainButtonStyle())
            
            Spacer()
        }
        .fullScreenCover(isPresented: $viewModel.isPresentingImagePicker, content: {
            ImagePicker(sourceType: viewModel.sourceType, completionHandler: viewModel.didSelectImage)
        })
    }
    //this is the error popup//
    .errorView(text: $errorText)
    
    VStack {
        TextField("Recipe Name", text: $recipeName).padding(.bottom).multilineTextAlignment(.leading).font(.title).padding(.leading).overlay(RoundedRectangle(cornerRadius: 10).stroke(nameErrorColor, lineWidth: 1).textFieldStyle(PlainTextFieldStyle()).frame(width: 300, height: 50, alignment: .leading).padding(.trailing, UIScreen.main.bounds.size.width / 5).padding(.bottom))
        List {
            //using zip, as safer than enumerated
            ForEach(Array(zip(pubRecArray.recipeArrayPublished.indices, pubRecArray.recipeArrayPublished)), id: .0) { index, element in
                HStack {
                    //Text(String(stepNumber[index]) + ".").bold()
                    //EditorView(container: self.$recipeStep, index: index, text: recipeStep[index])
                    TextField("", text: Binding<String>(get: { element }, set: { pubRecArray.recipeArrayPublished[index] = $0 }))
                }
            }
            .onDelete(perform: removeRows)
            HStack {
                TextField("Step (textFieldCount)", text: $stepInfo).multilineTextAlignment(.leading).padding(.leading).overlay(
                    RoundedRectangle(cornerRadius: 10).stroke(stepErrorColor, lineWidth: 1).textFieldStyle(PlainTextFieldStyle()).frame(width:100, height: 30, alignment: .leading).padding(.trailing, UIScreen.main.bounds.size.width / 2))
                
                Spacer()
                
                Button(action: {
                    manageAddStepFlow()
                    //vm.getRecipeSteps()
                }) {
                    Image(systemName: "plus")
                }
                .padding()
            }
        }
        //added listStyle to allow list to expand to fill safe area
        .listStyle(PlainListStyle())
    }
    Spacer()
    HStack {
        Button("Cancel") {
            presentationMode.wrappedValue.dismiss()
        }
        .cornerRadius(15)
        .frame(width: 75, height: 75)
        .foregroundColor(.white)
        .background(Color(red: 198/255, green: 40/255, blue: 40/255, opacity: 1.0))
        .clipShape(Circle())
        .font(.body)
        .overlay(RoundedRectangle(cornerRadius: 100)
                    .stroke(Color(red: 198/255, green: 40/255, blue: 40/255, opacity: 1.0)))
        Button("Finish") {
            errorCheckOnFinishClicked()
        }
        .cornerRadius(15)
        .frame(width: 75, height: 75)
        .foregroundColor(.black)
        .background(Color(red: 171/255, green: 245/255, blue: 209/255, opacity: 1.0))
        .clipShape(Circle())
        .font(.body)
        .overlay(RoundedRectangle(cornerRadius: 100)
                    .stroke(Color(red: 171/255, green: 245/255, blue: 209/255, opacity: 1.0)))
        
    }
    .navigationTitle("Add Recipe")
    .toolbar {
        ToolbarItem(placement: .navigationBarTrailing) {
            EditButton()
        }
    }
}

}

2

Answers


  1. Edit:

    You should restructure your code in "AddItemView" to be more modular.
    In any case,
    try this until you restructure the code:

    struct AddItemView: View {
        // ......
        
        var body: some View {
            Group {  // <--- here
                // ...... the messy code that should be made more modular
            }
            .navigationTitle("Add Recipe")
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    EditButton()
                }
            }
        }
    }
    

    Edit:

    You could structure your code with separate structs.
    "…will that lead to fix", well I don’t know but you will
    certainly understand your code better if it’s organised well.

    Another simple way is to do something like this with each major modules you have:

    var body: some View {
        ZStack {
            theAlertView
        }
        ....
     }
    
    var theAlertView: some View {
        HStack {
            Spacer()
            Button(action: {
                showingAlert = true
            }) {
                Image(systemName: viewModel.buttonImage)
            }
           .....
          .fullScreenCover(isPresented: $viewModel.isPresentingImagePicker, content: {
            ImagePicker(sourceType: viewModel.sourceType, completionHandler: viewModel.didSelectImage)
        })
    } 
    
    Login or Signup to reply.
  2. In your addItemView() wrap everything in the body in a VStack. TabView will create a new tab for everything that is directly underneath body. In your case it is a seperate tab for your ZStack, VStack, Spacer (maybe), and HStack. Once you wrap it all in a VStack then it will only create a single tab with everything inside that VStack

    struct AddItemView: View {
    
    // ...
    
    var body: some View {
        VStack {
            ZStack {
                // code
            }
        
            VStack {
                // Code
            }
            Spacer()
            HStack {
                // Code    
            }
            .navigationTitle("Add Recipe")
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    EditButton()
                }
            }
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search