How to prevent the keyboard from closing when typing in a UITextField embedded in a UICollectionView header cell using Swift?

Viewed 73

I want to search a UICollectionView using a custom UITextfield embedded in a UICollectionView header cell. I have a delegate method that passes inputed text to the main view controller, however, every letter you input in the textfield causes the keyboard to resign because the collection view is reloaded.

How to prevent the keyboard from closing when typing in a UITextField embedded in a UICollectionView header cell using Swift?

// SearchHeaderView

protocol SearchHeaderViewDelegate: AnyObject {
    func search(with searchString: String)
}

class SearchHeaderView: UICollectionViewCell, UITextFieldDelegate {

    weak var delegate: SearchHeaderViewDelegate?

    lazy var searchContainerView: InputContainerView = {
        return InputContainerView(image: UIImage(named: "96_search_line")!,
                                  textField: searchTextField)
    }()

    let searchTextField = CustomTextField(placeholder: "Search",
                                          keyboard: .default,
                                          autoCapitalization: .words)

    override init(frame: CGRect) {
        super.init(frame: .zero)
        searchTextField.delegate = self
    }

    func textFieldDidChangeSelection(_ textField: UITextField) {
        if (searchTextField.text?.count)! != 0 {
            delegate?.search(with: textField.text!)
        }
    }
}

// ViewController

collectionView.register(SearchHeaderView.self, forSupplementaryViewOfKind:
                                UICollectionView.elementKindSectionHeader, withReuseIdentifier: "headerId")

func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
    let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier:
                                                                    "headerId", for: indexPath) as! SearchHeaderView
    header.delegate = self
    return header
}

extension ViewController: SearchHeaderViewDelegate {
    func search(with searchString: String) {
        print("TESTING: Search containing \(searchString)")
        // search function...
        collectionView.reloadData() // causes the keyboard to close
    }
}
1 Answers

So, it sounds like its performing the search function with every key press. Is there a way for you to add a debounce to the textfield? You can try set the delay for a long time.

Something like this

import Combine

var cancellables = Set<AnyCancellable>()

override func viewDidLoad() {
  super.viewDidLoad()
  applyCombineSearch()
}

//Initialise the publisher and subscriber for search
func applyCombineSearch() {
  let publisher = NotificationCenter.default.publisher(for: searchTextField.textDidChangeNotification, object: viewController.collectionView.searchTextField)
  publisher
    .map {
      ($0.object as! CustomTextField).text
  }
  .debounce(for: .seconds(20), scheduler: RunLoop.main)
  .sink(receiveValue: { (value) in
    DispatchQueue.global(qos: .userInteractive).async { [weak self] in
      // Perform search
      DispatchQueue.main.async {
        collectionView.reloadData()
      }
    }
  })
  .store(in: &cancellables)
}
Related