Search code examples
buttonswiftuinavigationuinavigationbar

Navigation Bar Item Move Automatically SwiftUI


I'm trying to show a navigation bar item on the right side and I got almost success, but I stuck at the last moment my navigation right button automatically move after showing the other view. Please check my code and screenshot given below.


struct NvaigationButton: View {
    @State private var showPopUpFlgInapp = false
    var body: some View {
        NavigationView {
            ZStack {
                ScrollView {
                    VStack {
                        Image("DemoImage1")
                            .resizable()
                            .aspectRatio(16/9, contentMode: .fit)
                    }
                    Spacer()
                }
            }
            .navigationBarTitle("", displayMode: .inline)
         .edgesIgnoringSafeArea(/*@START_MENU_TOKEN@*/.all/*@END_MENU_TOKEN@*/)
            .navigationBarBackButtonHidden(true)
            .navigationBarItems(leading:
                                    Button(action: {
                                    }) {
                                        HStack {
                                            Image( "BackButtonWithColor")
                                        }},trailing:  AnyView(self.trailingButton))
        }
    }
    
    var trailingButton: some View {
        HStack {
            if showPopUpFlgInapp != true {
                Button(action: {
                    showPopUpFlgInapp = true
                }) {
                    HStack {
                        Image("ThreeDotsWithBckground")
                    }
                }
                
            }else if showPopUpFlgInapp == true {
                showFlagInAppr(showPopUpFlgInapp:$showPopUpFlgInapp,action: {
                    showPopUpFlgInapp = false
                })
            }
        }
    }
}

struct showFlagInAppr: View {
    @Binding var showPopUpFlgInapp: Bool
    var action: () -> Void
    var body: some View {
        if showPopUpFlgInapp {
            ZStack {
                VStack(alignment:.leading,spacing:30) {
                    Button(action: action, label: {
                        Text("Flag as inappropriate")
                    })
                }
            }.padding(20)
            .background(Color.init(UIColor.init(displayP3Red: 29/255, green: 33/255, blue: 33/255, alpha: 1.0)))
            .foregroundColor(.white)
            .cornerRadius(10)
        }
    }
}

Screen Shot 1

Screen Shot 2

Screen Shot 3


Solution

  • A possible solution is to use a toolbar instead of navigationBarItems:

    struct NvaigationButton: View {
        @State private var showPopUpFlgInapp = false
        var body: some View {
            NavigationView {
                ZStack {
                    ScrollView {
                        VStack {
                            Image("DemoImage1")
                                .resizable()
                                .aspectRatio(16 / 9, contentMode: .fit)
                        }
                        Spacer()
                    }
                }
                .navigationBarTitle("", displayMode: .inline)
                .edgesIgnoringSafeArea(.all)
                .navigationBarBackButtonHidden(true)
                .toolbar { // <- add here
                    ToolbarItem(placement: .navigationBarLeading) {
                        Button(action: {}) {
                            HStack {
                                Image("BackButtonWithColor")
                            }
                        }
                    }
                    ToolbarItem(placement: .navigationBarTrailing) {
                        trailingButton
                    }
                }
            }
        }
    
        var trailingButton: some View {
            HStack {
                if showPopUpFlgInapp != true {
                    Button(action: {
                        showPopUpFlgInapp = true
                    }) {
                        HStack {
                            Image("ThreeDotsWithBckground")
                        }
                    }
    
                } else if showPopUpFlgInapp == true {
                    Text("") // this prevents `showFlagInAppr` from showing inline
                    showFlagInAppr(showPopUpFlgInapp: $showPopUpFlgInapp, action: {
                        showPopUpFlgInapp = false
                    })
                }
            }
        }
    }
    

    Note: with the current behaviour of the toolbar, we need to add an extra empty Text as in this answer to prevent the showFlagInAppr from showing inline.