Реализация функции поиска в UICollectionView в UICollectionViewCell - PullRequest
1 голос
/ 26 октября 2019

Я хочу реализовать функцию поиска в UICollectionView в UICollectionViewCell. То, чего я пытаюсь добиться, - это пролистывание страниц с панелью поиска. Ранее я набрал несколько страниц с помощью панели поиска, но не смог провести пальцем по экрану, и чтобы соответствовать моему приложению для Android, мне нужно, чтобы оно было доступно для просмотра. Это руководство, которое я следовал, о том, как сделать его способным к прокруткеНазовите это ChildFrame.

Так что я могу анализировать текст поиска из MainFrame в ChildFrame и фильтровать массив данных в ChildFrame. Проверяя это в журнале консоли, все работает как положено. Отфильтрованный результат правильный. Но мой ChildFrame не обновляется до последнего массива данных. Вот код ниже.

Вот код для ChildFrame

class ChildFrameCell1: UICollectionViewCell, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
    let cellId = "cellId"

    var dataArray = [CustomObject]()

    var filteredData = [CustomObject]()

    var isFiltering: Bool = false

    var mainFrame: MainFrame?

    lazy var collectionView: UICollectionView = {
        let layout = UICollectionViewFlowLayout()
        layout.sectionInset = UIEdgeInsets(top: 4, left: 0, bottom: 0, right: 0)
        layout.minimumInteritemSpacing = 0.0
        let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
        cv.backgroundColor = .white
        cv.dataSource = self
        cv.delegate = self
        return cv
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        populateCollectionView()
        collectionView.register(CustomCell.self, forCellWithReuseIdentifier: cellId)

        addSubview(collectionView)
        collectionView.anchor(top: self.topAnchor, left: self.leftAnchor, bottom: self.bottomAnchor, right: self.rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)

    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func searchTypeAndText(type: String, text: String, filtering: Bool) {
        isFiltering = filtering
        filteredData = dataArray.filter({( object : CustomObject) -> Bool in
            if type == "type" {
                return object.type.lowercased().contains(text.lowercased())
            } else {
                return object.type.lowercased().contains(text.lowercased())
            }
        })
        DispatchQueue.main.async {
            self.collectionView.reloadData()
            self.collectionView.layoutSubviews()
        }
    }

    func populateCollectionView() {
    // load data into dataArray
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        if isFiltering {
        // during searching this will be triggered and return the correct count for the filteredData
            return filteredData.count
        } else {
            return dataArray.count
        }
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! CustomCell
        var object: CustomObject
        // isFiltering is always false even when searching
        if isFiltering {
            // never called
            object = filteredData[indexPath.row]
        } else {
            // always called even when searching
            object = dataArray[indexPath.row]
        }
        // do cell things here
        return cell
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: collectionView.frame.size.width - 8, height: 120)
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 4
    }

    func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
        cell.contentView.layer.masksToBounds = true
        let radius = cell.contentView.layer.cornerRadius
        cell.layer.shadowPath = UIBezierPath(roundedRect: cell.bounds, cornerRadius: radius).cgPath
    }
}

Вот код для MainFrame

class MainFrame: UICollectionViewController, UICollectionViewDelegateFlowLayout {

    let searchController = UISearchController(searchResultsController: nil)

    let cellId = "cellId"

    let childFrameCell1Id = "cell1Id"

    let childFrameCell2Id = "cell2Id"

    var childFrameCell1: ChildFrameCell1!

    var childFrameCell2: ChildFrameCell2!

    lazy var topBar: CustomTopBar = {
        let tb = CustomTopBar()
        tb.mainFrame = self
        return tb
    }() // Top bar sliding indicator

    override func viewDidLoad() {
        super.viewDidLoad()
        configureView()
        configureSearchBar()
        configureCollectionView()
        setupTopBar()
    }

    func configureCollectionView() {
        if let flowLayout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
            flowLayout.scrollDirection = .horizontal
            flowLayout.minimumLineSpacing = 0
            flowLayout.minimumInteritemSpacing = 0
        }
        collectionView.backgroundColor = .white
        collectionView.register(ChildFrameCell1.self, forCellWithReuseIdentifier: childFrameCell1Id)
        collectionView.register(ChildFrameCell2.self, forCellWithReuseIdentifier: childFrameCell2Id)
        collectionView.translatesAutoresizingMaskIntoConstraints = false
        collectionView.isPagingEnabled = true
        collectionView.showsHorizontalScrollIndicator = false
        collectionView.collectionViewLayout.invalidateLayout()
        collectionView.contentInset = UIEdgeInsets(top: 45, left: 0, bottom: 0, right: 0)
        collectionView.scrollIndicatorInsets = UIEdgeInsets(top: 45, left: 0, bottom: 0, right: 0)
        collectionView.contentInsetAdjustmentBehavior = UIScrollView.ContentInsetAdjustmentBehavior.never

        childFrameCell1 = ChildFrameCell1()
        childFrameCell2 = ChildFrameCell2()
    }

    func setupTopBar() {
        // add top bar
    }

    func configureView() {
        // set up view
    }

    func configureSearchBar() {
        searchController.searchResultsUpdater = self
        searchController.obscuresBackgroundDuringPresentation = false
        searchController.searchBar.placeholder = "Search"
        searchController.searchBar.tintColor = .white
        searchController.searchBar.barTintColor = .white
        if let tf = searchController.searchBar.value(forKey: "searchField") as? UITextField {
            tf.textColor = UIColor.white
            if let backgroundView = tf.subviews.first {
                backgroundView.backgroundColor = .white
                backgroundView.layer.cornerRadius = 10
                backgroundView.clipsToBounds = true
            }
        }
        navigationItem.searchController = searchController
        definesPresentationContext = true
        searchController.searchBar.scopeButtonTitles = ["Type1", "Type2"]
        searchController.searchBar.delegate = self
    }

    func searchBarIsEmpty() -> Bool {
        return searchController.searchBar.text?.isEmpty ?? true
    }

    func isFiltering() -> Bool {
        let searchBarScopeIsFiltering = searchController.searchBar.selectedScopeButtonIndex != 0
        return searchController.isActive && (!searchBarIsEmpty() || searchBarScopeIsFiltering)

    }


    func filterContentForSearchText(_ searchText: String, scope: String = "Location") {
        let visibleRect = CGRect(origin: collectionView.contentOffset, size: collectionView.bounds.size)
        let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
        let visibleIndexPath = collectionView.indexPathForItem(at: visiblePoint)
        if visibleIndexPath?.row == 0 { 
// find the current view and parse search text into childFrame
            childFrameCell1.searchTypeAndText(type: scope, text: searchText, filtering: isFiltering())
        } else {
            childFrameCell2.searchTypeAndText(type: scope, text: searchText, filtering: isFiltering())
        }
    }

    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 2 // 2 pages
    }

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

        let id: String

        currentView = indexPath.item
        if currentView == 0 {
            id = childFrameCell1Id
        } else {
            id = childFrameCell2Id
        }
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: id, for: indexPath) as! ChildFrameCell1
        cell.mainFrame = self
        return cell
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: view.frame.width, height: view.frame.height - 50)
    }
}

extension MainFrame: UISearchResultsUpdating {
    func updateSearchResults(for searchController: UISearchController) {
        let searchBar = searchController.searchBar
        let scope = searchBar.scopeButtonTitles![searchBar.selectedScopeButtonIndex]
        filterContentForSearchText(searchController.searchBar.text!, scope: scope)
        }
    }
}
extension MainFrame: UISearchBarDelegate {
    func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
        filterContentForSearchText(searchBar.text!, scope: searchBar.scopeButtonTitles![selectedScope])
    }
}

ChildFrameCell2 является подклассом ChildFrameCell1

Когда я ввожу текст в строку поиска в MainFrame, он не перезагружает collectionView в новый фильтрованные данные, даже если в фильтрованных данных содержатся данные. Я пробовал много способов сделать это, но все еще не смог перезагрузить collectionView. Я даже пытался использовать DispatchGroup, но результат все тот же. Фильтрация не является проблемой, все работает соответственно, за исключением перезагрузки collectionView.

Спасибо за чтение этого длинного поста. Если вам нужен код из MainFrame, дайте мне знать.

...