The following UIKit swift app uses a table view with 2 sections.
The first section displays a custom cell with a text view, which was added to the cell’s contentView
and anchored to the ladder’s layoutMarginsGuide
’s top, bottom, leading and trailing anchors.
The second section displays a custom cell that is like the former but with a text field instead of a text view.
Both sections have titles defined in the tableView(_:cellForRowAt:)
method.
If you run the app, you will see that the text view’s text is not vertically aligned to it’s section’s title, whereas the text field’s is.
How do I align the text view’s text as well?
import UIKit
class ViewController: UIViewController {
let tableView = UITableView()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(tableView)
tableView.frame = view.bounds
tableView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
tableView.dataSource = self
tableView.register(TextViewCell.self, forCellReuseIdentifier: TextViewCell.identifier)
tableView.register(TextFieldCell.self, forCellReuseIdentifier: TextFieldCell.identifier)
}
}
extension ViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
2
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
tableView.dequeueReusableCell(withIdentifier: TextViewCell.identifier, for: indexPath)
} else {
tableView.dequeueReusableCell(withIdentifier: TextFieldCell.identifier, for: indexPath)
}
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
"Title \(section)"
}
}
extension UITableViewCell {
static var identifier: String {
"\(Self.self)"
}
}
class TextViewCell: UITableViewCell {
let textView: UITextView = {
let tv = UITextView()
tv.text = "Text view"
tv.font = .preferredFont(forTextStyle: .title2)
tv.backgroundColor = .systemRed
tv.isScrollEnabled = false
return tv
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(textView)
textView.pin(to: contentView.layoutMarginsGuide)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class TextFieldCell: UITableViewCell {
let textField: UITextField = {
let tf = UITextField()
tf.text = "Text field"
tf.backgroundColor = .systemBlue
return tf
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(textField)
textField.pin(to: contentView.layoutMarginsGuide)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Here's how the pin(to:) function is defined in case you're wondering:
import UIKit
extension UIView {
func pin(
to object: CanBePinnedTo,
top: CGFloat = 0,
bottom: CGFloat = 0,
leading: CGFloat = 0,
trailing: CGFloat = 0
) {
self.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
self.topAnchor.constraint(equalTo: object.topAnchor, constant: top),
self.bottomAnchor.constraint(equalTo: object.bottomAnchor, constant: bottom),
self.leadingAnchor.constraint(equalTo: object.leadingAnchor, constant: leading),
self.trailingAnchor.constraint(equalTo: object.trailingAnchor, constant: trailing),
])
}
}
@MainActor
protocol CanBePinnedTo {
var topAnchor: NSLayoutYAxisAnchor { get }
var bottomAnchor: NSLayoutYAxisAnchor { get }
var leadingAnchor: NSLayoutXAxisAnchor { get }
var trailingAnchor: NSLayoutXAxisAnchor { get }
}
extension UIView: CanBePinnedTo { }
extension UILayoutGuide: CanBePinnedTo { }