英文:
SwiftUI Search Bar Animation
问题
这是我的WelcomeView.swift代码:
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("欢迎使用应用!")
.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("搜索", 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("允许位置服务")
.font(.title)
}
.frame(width: 500, height: 70)
})
}
.zIndex(0)
}
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
这是LocationSearch.swift代码:
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)
}
}
在这个GIF中,点击搜索栏后,搜索栏平滑地移动到屏幕顶部,淡化其他内容,并弹出键盘。然后用户可以开始输入,结果将显示出来。
我已经完成了所有的搜索逻辑,但我无法让UI在点击搜索栏时以我设想的方式反应。
英文:
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.
答案1
得分: 1
ObservableObject
s are a thing of the past. When programming for visionOS you should be using @Observable
.
ObservableObject
s have always been inefficient and terrible with animation because they cause a complete redraw instead of a targeted redraw.
Apple has completely changed how models work.
英文:
ObservableObject
s are a thing of the past. When programming for visionOS you should be using @Observable
ObservableObject
s 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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论