skip to Main Content

I am trying to make the search box in .searchable stick to the top without moving when there is no navigationBarTitle. Basically, when the box gets focused, there is an animation that moves the box upward and I would like to prevent that from hapenning. I just want the searchbox to stay stationary at the top, with just the cancel button coming from the right when the box is focused.

I tried all type of things such as .navigationBarHidden(true) but this totally removes the search bar as a whole.

Tried to add some spacer under in a vstack but it didnt push the bar up when unfocused, i tried to add some .ignoreSafeArea() but it didnt work. I tried to add a geometryReader and make the screen height larger than the display but it didnt move things up.

My codes:

struct SearchBarSM: View {
    
    @State var searchtxt:String = ""
    
    var body: some View {
        GeometryReader { geo in
            NavigationStack {
                ZStack {
                    VStack {
                        Text("Hello stackoverflow")
                    }
                }
                .navigationBarTitle("")
                .searchable(text: $searchtxt, prompt: "Search") {
                }
                .preferredColorScheme(.dark)
            }
        }
    }
}

When Unfocused:
enter image description here

When Focused:
enter image description here

The box moves up when focused.

2

Answers


  1. As devdchaudhary said in the comments, I doubt this can be changed. You need to make your own search bar, and put it in the .principal position of the toolbar.

    It’s not that difficult to make your own search bar. Here, I have made something that behaves similar to the system’s search bar. Adjust the colors and paddings as you see fit.

    struct CustomSearchBar: View {
        @Binding var searchText: String
        
        @State var active = false
        
        @Namespace var search
        
        var body: some View {
            HStack {
                HStack {
                    Image(systemName: "magnifyingglass").foregroundColor(.gray)
                    TextField("Search", text: $searchText, onEditingChanged: { editing in
                        withAnimation {
                            active = editing
                        }
                    })
                }
                .padding(7)
                .background(Color(white: 0.9))
                .cornerRadius(10)
                .padding(.horizontal, active ? 0 : 50)
                
                Button("Cancel") {
                    withAnimation {
                        active = false
                    }
                }
                .opacity(active ? 1 : 0)
                .frame(width: active ? nil : 0)
            }
        }
    }
    

    Usage:

    .toolbar {
        ToolbarItem(placement: .principal) {
            CustomSearchBar(searchText: $searchText)
        }
    }
    
    Login or Signup to reply.
  2. To achieve the behavior you described, you have to make a search bar view custom and then put it into the SearchBarSM view.

    Example code:

    SearchableCustom: View

    struct SearchableCustom: View {
        
        @Binding var searchtxt: String
        @FocusState private var isSearchFocused: Bool // Track focus state
        
        var body: some View {
            HStack {
                HStack {
                    Image(systemName: "magnifyingglass")
                    TextField("Search", text: $searchtxt)
                        .focused($isSearchFocused) // Track focus state
                        .padding(.horizontal, 10)
                        .padding(.vertical, 8)
                }
                .padding(.horizontal)
                .background(Color(.secondarySystemBackground))
                .cornerRadius(10)
                .overlay(RoundedRectangle(cornerRadius: 10).stroke(Color.gray, lineWidth: 1))
                
                if isSearchFocused {
                    Button("Cancel") {
                        searchtxt = ""
                        withAnimation(.spring()) {
                            isSearchFocused = false
                        }
                    }
                    .transition(.move(edge: .trailing)) // Add animation for cancel button
                }
            }
            .frame(maxWidth: .infinity)
            .padding(.horizontal)
        }
    }
    

    SearchBarSM: View

    struct SearchBarSM: View {
        
        @State var searchtxt:String = ""
        
        var body: some View {
            VStack {
                SearchableCustom(searchtxt: $searchtxt)
                Text("Hello stackoverflow")
            }
            .frame(maxHeight: .infinity, alignment: .top)
            .preferredColorScheme(.dark)
        }
    }
    

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search