I have a messaging app that has the typical UI design of a text field at the bottom of a full screen table view. I am setting that text field to be the view controller\'s
From code (Swift 4). Idea - monitoring layoutMarginsDidChange
event and adjusting intrinsicContentSize
.
public final class AutoSuggestionView: UIView {
private lazy var tableView = UITableView(frame: CGRect(), style: .plain)
private var bottomConstraint: NSLayoutConstraint?
var streetSuggestions = [String]() {
didSet {
if streetSuggestions != oldValue {
updateUI()
}
}
}
var handleSelected: ((String) -> Void)?
public override func initializeView() {
addSubview(tableView)
setupUI()
setupLayout()
// ...
updateUI()
}
public override var intrinsicContentSize: CGSize {
let size = super.intrinsicContentSize
let numRowsToShow = 3
let suggestionsHeight = tableView.rowHeight * CGFloat(min(numRowsToShow, tableView.numberOfRows(inSection: 0)))
//! Explicitly used constraint instead of layoutMargins
return CGSize(width: size.width,
height: suggestionsHeight + (bottomConstraint?.constant ?? 0))
}
public override func layoutMarginsDidChange() {
super.layoutMarginsDidChange()
bottomConstraint?.constant = layoutMargins.bottom
invalidateIntrinsicContentSize()
}
}
extension AutoSuggestionView {
private func updateUI() {
backgroundColor = streetSuggestions.isEmpty ? .clear : .white
invalidateIntrinsicContentSize()
tableView.reloadData()
}
private func setupLayout() {
let constraint0 = trailingAnchor.constraint(equalTo: tableView.trailingAnchor)
let constraint1 = tableView.leadingAnchor.constraint(equalTo: leadingAnchor)
let constraint2 = tableView.topAnchor.constraint(equalTo: topAnchor)
//! Used bottomAnchor instead of layoutMarginGuide.bottomAnchor
let constraint3 = bottomAnchor.constraint(equalTo: tableView.bottomAnchor)
bottomConstraint = constraint3
NSLayoutConstraint.activate([constraint0, constraint1, constraint2, constraint3])
}
}
Usage:
let autoSuggestionView = AutoSuggestionView()
// ...
textField.inputAccessoryView = autoSuggestionView
Result: