[英]How to make a pull down search bar in SwiftUI
I want to make a pull down search bar in my app using SwiftUI and have to be compatible with iOS13, so I couldn't use ScrollViewReader.我想使用 SwiftUI 在我的应用程序中创建一个下拉搜索栏,并且必须与 iOS13 兼容,所以我不能使用 ScrollViewReader。 I tried using Introspect , but I didn't understand what it does and how it works, because the documentation doesn't explain how to do stuff for ScrollView other than pull down to refresh.
我尝试使用Introspect ,但我不明白它的作用和工作原理,因为除了下拉刷新之外,文档没有解释如何为 ScrollView 做一些事情。 I used introspect for TextField to become and resign FirstResponder, and it works, but when I use introspect for scrollview, the function only runs when the scroll view first appeared.
我使用 Introspect for TextField 成为并退出 FirstResponder,它可以工作,但是当我使用 introspect for scrollview 时,function 仅在滚动视图首次出现时运行。
@State private var willSearch = false
...
.introspectTextField{ textfield in
textfield.returnKeyType = .done
if willSearch {
textfield.becomeFirstResponder()
}else{
textfield.resignFirstResponder()
}
}
// this works when `willSearch` changed value
This is how my ScrollView introspection looks like这就是我的 ScrollView 内省的样子
extension UIScrollView {
var isBouncing: Bool {
return (contentOffset.y + contentInset.top < 0)
}
}
...
.introspectScrollView { scroll in
if scroll.isDragging{
self.willSearch = scroll.isBouncing;
}
}
// this doesn't work
I also tried detecting scroll by following this suggestion , but it's not very effective, and I can hear my MacBook fan spinning louder than normal, so it probably will impact the performance.我也尝试按照这个建议检测滚动,但它不是很有效,而且我可以听到我的 MacBook 风扇旋转的声音比平时大,所以它可能会影响性能。
This is roughly how I want it to behave Pull down search bar as seen in Telegram这大致就是我希望它的行为方式下拉搜索栏,如 Telegram 中所示
I prefer to use UIKit
to implement inapp navigation and only use SwiftUI
to build screen UI.我更喜欢使用
UIKit
来实现应用内导航,只使用SwiftUI
来构建屏幕 UI。 So I work with UIHostingController
+ UINavigationController
and can easily integrate UISearchController
.所以我使用
UIHostingController
+ UINavigationController
并且可以轻松集成UISearchController
。 For example like this:例如像这样:
import UIKit
import SwiftUI
class ViewController: UIHostingController<Content>, UISearchResultsUpdating {
private let viewModel = ViewModel()
init() {
super.init(rootView: Content(viewModel: viewModel))
title = "Test"
}
@objc required dynamic init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
self.navigationItem.searchController = searchController
navigationController?.view.setNeedsLayout() // this is needed for iOS 13 only
}
func updateSearchResults(for searchController: UISearchController) {
viewModel.searchDidChange(searchController.searchBar.text ?? "")
}
}
struct Content: View {
@ObservedObject var viewModel: ViewModel
var body: some View {
ScrollView {
VStack {
ForEach(viewModel.items, id: \.self) { item in
Text(item)
.frame(maxWidth: .infinity)
}
}
}
}
}
class ViewModel: ObservableObject {
@Published var items: [String]
private let allItems: [String]
init() {
self.allItems = (0..<100).map { "\($0)" }
self.items = allItems
}
func searchDidChange(_ text: String) {
items = allItems.filter {
$0.starts(with: text)
}
}
}
WARNING: you have to disable Main.storyboard
( https://sarunw.com/posts/how-to-create-new-xcode-project-without-storyboard/ ) and load root controller manually.警告:您必须手动禁用
Main.storyboard
( https://sarunw.com/posts/how-to-create-new-xcode-project-without-storyboard/ ) 并手动加载根 Z594C103F52C6E04C31AZ8 For example like this:例如像这样:
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let scene = (scene as? UIWindowScene) else { return }
let window = UIWindow(windowScene: scene)
window.rootViewController = UINavigationController(rootViewController: ViewController())
window.makeKeyAndVisible()
self.window = window
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.