0

I have a search bar in SwiftUi and it doesn't react the way I am wanting it to. I have gone through a few attempts at using .overlay and .zIndex but that did not work as intended. It added the SearchView, but it still displayed the other text. Here's the code I have currently. What I'm intending to do is search for a location using MapKit, which I have working. I included the code for that file in case it's needed. I just cannot get the search bar to react the way I want.

This is my WelcomeView.Swift code:

import SwiftUI

struct WelcomeView: View {
    @EnvironmentObject var locationManager: LocationManager
    @ObservedObject var locationSearch: LocationSearch
    @State private var isSearching = false
    
    var body: some View {
        
        VStack {
            
            if isSearching {
                LocationSearchView(locationSearch: locationSearch)
                    .zIndex(1)
//                    .background(Color.blue)
            } else {
                VStack(spacing: 10) {
                    Text("Welcome to App!")
                        .bold().font(.largeTitle)
                    
                    Text("Blah Blah Blah Blah Blah Blah")
                        .font(.title)
                    
                }
                .multilineTextAlignment(.center)
                .padding()
                
                VStack() {
                    Text("Blah Blah Blah Blah Blah")
                    Text("Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah")
                }
                .padding()
                .font(.headline)
                
                ZStack {
                    
                    VStack {
                        TextField("Search", text: $locationSearch.queryFragment, onEditingChanged: { isEditing in isSearching = isEditing
                        })
                        .padding(.horizontal)
                        .padding(.vertical, 8)
                        .frame(width: 535, height: 70)
                        .background(.thinMaterial)
                        .cornerRadius(10)
        
                        Button(action: {
                            locationManager.requestLocation()
                        }, label: {
                            HStack {
                                Image(systemName: "location.fill")
                                Text("Allow Location Services")
                                    .font(.title)
                            }
                            .frame(width: 500, height: 70)
                        })
                    }
                    .zIndex(0)
                }
            }
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
    }

}

This is the LocationSearch.swift code:

import Foundation
import Combine
import MapKit

class LocationSearch: NSObject, ObservableObject {
    
    enum LocationStatus: Equatable {
        case idle
        case noResults
        case isSearching
        case error(String)
        case result
    }
    
    @Published var queryFragment: String = ""
    @Published private(set) var status: LocationStatus = .idle
    @Published private(set) var searchResults: [MKLocalSearchCompletion] = []
    
    private var queryCancellable: AnyCancellable?
    private let searchCompleter: MKLocalSearchCompleter!
    
    init(searchCompleter: MKLocalSearchCompleter = MKLocalSearchCompleter()) {
        self.searchCompleter = searchCompleter
        super.init()
        self.searchCompleter.delegate = self
        
        queryCancellable = $queryFragment
            .receive(on: DispatchQueue.main)
            .debounce(for: .milliseconds(250), scheduler: RunLoop.main, options: nil)
            .sink(receiveValue: { fragment in
                self.status = .isSearching
                if !fragment.isEmpty {
                    self.searchCompleter.queryFragment = fragment
                } else {
                    self.status = .idle
                    self.searchResults = []
                }
        })
    }
}

extension LocationSearch: MKLocalSearchCompleterDelegate {
    func completerDidUpdateResults(_ completer: MKLocalSearchCompleter) {
        self.searchResults = completer.results.filter({ $0.subtitle == "" })
        self.status = completer.results.isEmpty ? .noResults : .result
    }
    
    func completer(_ completer: MKLocalSearchCompleter, didFailWithError error: Error) {
        self.status = .error(error.localizedDescription)
    }
}

This is a gif of how I am wanting it to function

In this GIF, upon tapping the search bar, the search bar moves smoothly to the top of the screen, fades everything else out, and brings up the keyboard. Then the user can start typing and results will display.

I have all of the search logic working but I can't get the UI to react in the way I am envisioning when tapping the search bar.

Cody
  • 1

1 Answers1

1

ObservableObjects are a thing of the past. When programming for visionOS you should be using @Observable

https://developer.apple.com/documentation/swiftui/migrating-from-the-observable-object-protocol-to-the-observable-macro

ObservableObjects have always been inefficient and terrible with animation because they cause a complete redraw instead of a targeted redraw.

Apple as completely changed how models work.

https://developer.apple.com/documentation/swiftui/managing-model-data-in-your-app

lorem ipsum
  • 21,175
  • 5
  • 24
  • 48
  • Thank you. I remember seeing something about @Observable and forgot about changing the code for that. I’ll try to re-write the code and see what happens. – Cody Jun 28 '23 at 19:04