I’m working on preexistent code.
I have a textfield inside a section of my tableview, anyway I try to hide the keyboard it ends up removing my view from the superview.
By adding a breakpoint inside the removeFromSuperview()
I can see the resignFirstResponder()
is the cause of it.
- I can’t find any explicit call to
removeFromSuperview()
- The table view is not realoding, because no UITableViewDatasource function is being executed
- I registered the table view cell used as a section and
dequeueReusableCell
, I also tried calling it directly withBundle.main.loadNib
- I also tried hiding the keyboard using the UIApplication singleton to see if it acted the same, and it did.
ParentTableViewController
- The first section doesn’t exist, that’s why its height is zero
- The table view is built so there’s a cellOne, section and cellTwo
- the last cell (cellTwo) is another TableView, when I scroll, the section stays as a header
extension ParentTableViewController: UITableViewDataSource, UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return section == 0 ? 0 : 105
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
guard section == 1 else { return nil }
let headerView = tableView.dequeueReusableCell(withIdentifier: SectionWithTextfieldCell.identifier) as! SectionWithTextfieldCell
headerView.delegate = self
headerView.setupUI(segmentIndexSelected: segmentIndexSelected, membersCount: campData.attributes?.members_count ?? 0, searchedText: viewModel?.searchUsername)
return headerView
}
func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch indexPath.section {
case 0:
let cell = tableView.dequeueReusableCell(withIdentifier: OtherCellOne.identifier) as! OtherCellOne
cell.delegate = self
cell.setup(campData: campData, descriptionLblLines: descriptionLblLines, segmentIndexSelected: segmentIndexSelected)
return cell
default:
let cell = tableView.dequeueReusableCell(withIdentifier: OtherCellTwo.identifier, for: indexPath) as! OtherCellTwo
cell.delegate = self
cell.setup(campData: campData, members: members, rooms: rooms, segmentIndexSelected: segmentIndexSelected, loadingUsers: viewModel?.loadingUsers)
return cell
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: false)
self.view.endEditing(true)
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cell.layoutIfNeeded()
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
switch indexPath.section {
case 1:
return heightMembersRooms
default:
return UITableView.automaticDimension
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
switch indexPath.section {
case 1:
return heightMembersRooms
default:
return UITableView.automaticDimension
}
}
}
SectionWithTextfieldCell
class SectionWithTextfieldCell: UITableViewCell {
@IBOutlet weak var searchBarTrailingConstraint: NSLayoutConstraint!
@IBOutlet weak var searchBar: UISearchBar!
@IBOutlet weak var cancelButton: UIButton!
weak var delegate: Delegate?
static var identifier: String {
String(describing: self)
}
override func awakeFromNib() {
super.awakeFromNib()
}
@IBAction func pressedCancel(_ sender: Any) {
resetSearch() { [weak self] in
guard let self else { return }
searchBar.searchTextField.text = ""
delegate?.search(username: "")
}
}
func setupUI(segmentIndexSelected: Int, membersCount: Int, searchedText: String?) {
searchBar.searchTextField.text = searchedText
setupSearchBar()
}
func setupSearchBar() {
searchBar?.delegate = self
searchBar?.backgroundImage = UIImage()
searchBar?.placeholder = String(localized: "Search for users by username...")
searchBar?.clipsToBounds = true
searchBar?.searchTextField.textColor = UIColor.init(hexString: "#585858")
searchBar?.searchTextField.font = FontKit.roundedFont(ofSize: 15, weight: .regular)
searchBar?.searchTextField.layer.cornerRadius = 25
searchBar?.searchTextField.layer.masksToBounds = true
searchBarTrailingConstraint.constant = 0
cancelButton.setTitle(String(localized: "Cancel"), for: .normal)
cancelButton.titleLabel?.font = FontKit.roundedFont(ofSize: 12, weight: .regular)
}
protocol Delegate: AnyObject {
func search(username: String)
func scrollToSearchBar()
}
func resetSearch(completion: (() -> Void)? = nil) {
UIView.animate(withDuration: 0.3, animations: { [weak self] in
guard let self else { return }
searchBarTrailingConstraint.constant = 0
}, completion: { [weak self] _ in
guard let self else { return }
searchBar.searchTextField.resignFirstResponder()
completion?()
})
}
}
// MARK: - UISearchBarDelegate
extension SectionWithTextfieldCell: UISearchBarDelegate {
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
resetSearch()
}
func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool {
UIView.animate(withDuration: 0.3, animations: { [weak self] in
guard let self else { return }
searchBarTrailingConstraint.constant = cancelButton.frame.width
self.layoutIfNeeded()
})
delegate?.scrollToSearchBar()
return true
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
delegate?.search(username: searchText)
}
}