微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在 SwiftUI 中制作下拉搜索栏

如何解决如何在 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
    }

}

enter image description here

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。