I'm playing around with the new UICollectionViewListCell
and UIContentConfiguration
s and they are awesome, but I can't figure out how to change the default cell height of 44 that UIKit
automatically sets for these cells. Here's an example cell:
class TextFieldCell: UICollectionViewListCell {
struct ContentConfiguration: UIContentConfiguration, Hashable {
struct Handlers: ContentConfigurationHandlers {
var onTextChanged: ((_ newText: String) -> Void)?
}
var handlers: Handlers?
var text: String?
var placeholder: String?
var keyboardType: UIKeyboardType?
func makeContentView() -> UIView & UIContentView {
ContentView(configuration: self)
}
func updated(for state: UIConfigurationState) -> TextFieldCell.ContentConfiguration {
guard let state = state as? UICellConfigurationState else { return self }
var updatedConfiguration = self
return updatedConfiguration
}
}
class ContentView: UIView, UIContentView, UITextFieldDelegate {
private var appliedConfiguration: TextFieldCell.ContentConfiguration!
var configuration: UIContentConfiguration {
get {
appliedConfiguration
}
set {
guard let newConfiguration = newValue as? TextFieldCell.ContentConfiguration else {
return
}
apply(configuration: newConfiguration)
}
}
let nameTextField: UITextField = UITextField()
init(configuration: TextFieldCell.ContentConfiguration) {
super.init(frame: .zero)
setupInternalViews()
apply(configuration: configuration)
}
required init?(coder: NSCoder) {
fatalError()
}
private func setupInternalViews() {
addSubview(nameTextField)
nameTextField.delegate = self
nameTextField.clearButtonMode = .always
nameTextField.autocapitalizationType = .sentences
nameTextField.addAction(UIAction(handler: { [unowned self] action in
textChanged()
}), for: .editingChanged)
NSLayoutConstraint.activate([
nameTextField.leadingAnchor.constraint(equalTo: leadingAnchor),
nameTextField.topAnchor.constraint(equalTo: topAnchor),
nameTextField.trailingAnchor.constraint(equalTo: trailingAnchor),
nameTextField.bottomAnchor.constraint(equalTo: bottomAnchor),
nameTextField.heightAnchor.constraint(equalToConstant: 200) // Example height
])
}
/// Apply a new configuration.
/// - Parameter configuration: The new configuration
private func apply(configuration: TextFieldCell.ContentConfiguration) {
guard appliedConfiguration != configuration else { return }
appliedConfiguration = configuration
nameTextField.text = appliedConfiguration.text
nameTextField.placeholder = appliedConfiguration.placeholder
nameTextField.keyboardType = appliedConfiguration.keyboardType ?? .default
nameTextField.autocapitalizationType = .sentences
}
private func textChanged() {
appliedConfiguration.handlers?.onTextChanged?(nameTextField.text ?? "")
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
}
}
The important part is setting the layout constraints for the text field:
NSLayoutConstraint.activate([
nameTextField.leadingAnchor.constraint(equalTo: leadingAnchor),
nameTextField.topAnchor.constraint(equalTo: topAnchor),
nameTextField.trailingAnchor.constraint(equalTo: trailingAnchor),
nameTextField.bottomAnchor.constraint(equalTo: bottomAnchor),
nameTextField.heightAnchor.constraint(equalToConstant: 200) // Example height
])
I set the height to 200 (as an example). When I run this, I get this:
2020-11-08 11:12:01.805610+0100 Sophia[11924:720407] [LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
"<NSAutoresizingMaskLayoutConstraint:0x600001111f40 h=--& v=--& _TtCC6Sophia13TextFieldCell11ContentView:0x7fc0ed27a1c0.height == 44 (active)>",
"<NSLayoutConstraint:0x6000011198b0 UITextField:0x7fc0ed27a370.height == 200 (active)>",
"<NSLayoutConstraint:0x600001119810 V:|-(0)-[UITextField:0x7fc0ed27a370] (active, names: '|':_TtCC6Sophia13TextFieldCell11ContentView:0x7fc0ed27a1c0 )>",
"<NSLayoutConstraint:0x600001119b80 UITextField:0x7fc0ed27a370.bottom == _TtCC6Sophia13TextFieldCell11ContentView:0x7fc0ed27a1c0.bottom (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x6000011198b0 UITextField:0x7fc0ed27a370.height == 200 (active)>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful.
As you see, there's an auto-generated height constraint setting the height to 44
, which creates a conflict. Why is that there? And how can I change it?