如何解决如何在 SwiftUI 中制作下拉搜索栏
我想使用 SwiftUI 在我的应用程序中创建一个下拉搜索栏,并且必须与 iOS13 兼容,所以我无法使用 ScrollViewReader。我尝试使用 Introspect,但我不明白它的作用以及它是如何工作的,因为除了下拉刷新之外,文档没有解释如何为 ScrollView 做一些事情。我使用了 TextField 的 introspect 成为并退出了 FirstResponder,它可以工作,但是当我使用 introspect for scrollview 时,该功能仅在滚动视图首次出现时运行。
@State private var willSearch = false
...
.introspectTextField{ textfield in
textfield.returnKeyType = .done
if willSearch {
textfield.becomeFirstResponder()
}else{
textfield.resignFirstResponder()
}
}
// this works when `willSearch` changed value
这就是我的 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
我也尝试通过跟随 this suggestion 来检测滚动,但效果不是很好,而且我可以听到我的 MacBook 风扇比平时更响亮,因此它可能会影响性能。
这大致就是我希望它的行为Pull down search bar as seen in Telegram
解决方法
我更喜欢使用 UIKit
来实现应用内导航,只使用 SwiftUI
来构建屏幕 UI。所以我使用 UIHostingController
+ UINavigationController
并且可以轻松集成 UISearchController
。例如像这样:
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)
}
}
}
警告:您必须禁用 Main.storyboard
(https://sarunw.com/posts/how-to-create-new-xcode-project-without-storyboard/) 并手动加载根控制器。例如像这样:
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
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。