交互式下拉搜索栏

问题描述 投票:0回答:1

交互式下拉搜索栏

我正在尝试使用 UIViewPropertyAnimator 实现交互式下拉搜索栏。但我是 iOS 开发新手。所以我犯了很多错误。请查看此代码,给我任何解决方案。

import UIKit

class ViewController: UIViewController {
    private let searchController = UISearchController(searchResultsController: nil)
    let scrollView = UIScrollView()
    var transitionInProgress: Bool = false
    var searchAnimator: UIViewPropertyAnimator?
    var isSearchBarShowing: Bool = false
    var cachedSearchBarFrame: CGRect = .init()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.title = "Home"
        cachedSearchBarFrame = searchController.searchBar.frame
        self.navigationController?.navigationBar.backgroundColor = .white
        view.backgroundColor = .white
        view.addSubview(scrollView)
        scrollView.translatesAutoresizingMaskIntoConstraints = false
        
        scrollView.delegate = self
        
        searchController.searchResultsUpdater = self
        searchController.obscuresBackgroundDuringPresentation = false
        searchController.searchBar.placeholder = "Search"
        searchController.delegate = self
        
        navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .search, target: self, action: #selector(searchButtonTapped))
        NSLayoutConstraint.activate([
            scrollView.topAnchor.constraint(equalTo: view.topAnchor),
            scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])
        
        navigationItem.titleView = searchController.searchBar
        navigationItem.titleView?.alpha = 0
        
        searchAnimator = UIViewPropertyAnimator(duration: 2, curve: .easeIn) {
            self.searchController.searchBar.frame = self.cachedSearchBarFrame
            self.navigationItem.titleView?.alpha = 1
        }
        searchAnimator?.addCompletion { position in
            if position == .end {
                self.isSearchBarShowing = true
            } else if position == .start {
                self.searchAnimator?.isReversed = false
            }
        }

    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        scrollView.contentSize = .init(width: self.view.frame.width, height: 2000)
    }

    
    @objc func searchButtonTapped() {
        if isSearchBarShowing {
            hideSearchBar()
        } else {
            showSearchBar()
        }
    }
    
    func showSearchBar() {
        isSearchBarShowing = true
        
        searchController.searchBar.frame = CGRect(x: 0, y: -self.cachedSearchBarFrame.height, width: self.cachedSearchBarFrame.width, height: self.cachedSearchBarFrame.height)
        self.navigationItem.titleView?.alpha = 0
        // Apply animation
        UIView.animate(withDuration: 1) {
            self.searchController.searchBar.frame = self.cachedSearchBarFrame
            self.navigationItem.titleView?.alpha = 1
        }
    }

    func hideSearchBar() {
        isSearchBarShowing = false

        UIView.animate(withDuration: 1) {
            self.searchController.searchBar.frame = CGRect(x: 0, y: -self.cachedSearchBarFrame.height, width: self.cachedSearchBarFrame.width, height: self.cachedSearchBarFrame.height)
            self.navigationItem.titleView?.alpha = 0
        }
    }
    
}

extension ViewController: UISearchResultsUpdating {
    func updateSearchResults(for searchController: UISearchController) {
        // Implement your search logic here
    }
}

extension ViewController: UIScrollViewDelegate {
    
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let pullThreshold: CGFloat = -100

        if scrollView.contentOffset.y + scrollView.contentInset.top < pullThreshold {
            if !transitionInProgress && scrollView.isDragging && scrollView.isTracking {
                let fractionComplete = -(scrollView.contentOffset.y + 200) / 100
                searchAnimator?.fractionComplete = min(max(fractionComplete, 0), 1)
                print(min(max(fractionComplete, 0), 1))
                searchAnimator?.startAnimation()
            }
        }
    }
    
    func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
        let fractionComplete = -(scrollView.contentOffset.y + 200) / 100
        if fractionComplete < 1 && fractionComplete > 0 {
            searchAnimator?.isReversed = true
            searchAnimator?.startAnimation()
        }
    }

    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        searchAnimator?.stopAnimation(true)
        if !isSearchBarShowing {
            searchController.searchBar.frame = CGRect(x: 0, y: -self.cachedSearchBarFrame.height, width: self.cachedSearchBarFrame.width, height: self.cachedSearchBarFrame.height)
            self.navigationItem.titleView?.alpha = 0
            searchAnimator?.fractionComplete = 0
        }
    }

}

extension ViewController: UISearchControllerDelegate {
    
}

在这段代码中,我尝试实现一个下拉搜索栏,但它在第一次下拉时效果很好,但不适用于下一次后续拉动。请修复此代码中的错误。

ios swift uikit uisearchcontroller uiviewpropertyanimator
1个回答
0
投票

UISearchController
在控制器中呈现时具有默认动画。因此,你不必计算这些帧、alpha 等。而且它还在内部处理
showingState
。我更喜欢这种方法:

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    let pullThreshold: CGFloat = -100
    if scrollView.contentOffset.y + scrollView.contentInset.top < pullThreshold {
        //Keep your threshold as you wish
        showSearchBar()
    }
}

func showSearchBar() {
    guard self.presentedViewController !== searchController else { return }
    present(searchController, animated: true) //<- here
}

输出:

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.