My goal is to add button to the right hand side of a section header in a UITableView.
However, when I made my new target iOS15, I found that I had to adopt UIButton configuration to set the padding to the add icon in the button. The problem is that, configuration doesn't seem to have a "frame" property and passing a configuration to a button then setting its frame builds to show no button at all.
My new, faulty code is:
func tableView (_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let frame = tableView.frame
let headerView = UIView(frame: CGRect(x:0, y: 0, width: frame.size.width, height: frame.size.height)) // create custom view
let sectionName = hasSections ? sectionTasks[section].sectionName : nil
if sectionName != nil {
let view = UIView()
let label = UILabel()
... // Label config, skipping here
let tableWidth = tableView.frame.width
label.frame = CGRect(x: 5, y: 0, width: tableWidth, height: 30)
headerView.addSubview(label)
}
// My faulty button
var buttonConfig = UIButton.Configuration.filled()
buttonConfig.contentInsets = NSDirectionalEdgeInsets(top: 5, leading: 5, bottom: 5, trailing: 5)
buttonConfig.image = UIImage(named: "add_AsTemplate")
let xPos = tableView.frame.width-40-15
let button = UIButton(configuration: buttonConfig)
button.frame = CGRect(x: xPos, y: 0, width: 40, height: 40)
button.tag = section
button.addTarget(self, action: #selector(BaseTaskListVC.sectionNewTask_BtnPressed), for: .touchUpInside) // add selector called by clicking on the button
headerView.addSubview(button)
return headerView
}
My original button code (skipping context of parent function):
let xPos = tableView.frame.width-40-15
let button = UIButton(frame: CGRect(x: xPos, y: 0, width: 40, height: 40))
button.tag = section
button.imageEdgeInsets = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5 )
button.setImage(UIImage(named: "add_AsTemplate"), for: UIControl.State.normal)
button.addTarget(self, action: #selector(BaseTaskListVC.sectionNewTask_BtnPressed), for: .touchUpInside)
headerView.addSubview(button)
I've read the Apple documentation but it doesn't seem to address this explicitly. All the other SO threads on this show how to use configuration but not configuration + frame.
Original code:
With new configuration approach:
Lastly, I've tried the suggested answer:
var buttonConfig = UIButton.Configuration.plain()
buttonConfig.contentInsets = NSDirectionalEdgeInsets(top: 5, leading: 5, bottom: 5, trailing: 5)
var theImage: UIImage
if let img = UIImage(named: "add_AsTemplate") {
theImage = img
} else if let img = UIImage(systemName: "plus") {
// I don't have your "add_AsTemplate" image, so I'll use a SF Symbol
theImage = img
} else {
fatalError("Could not load a button image!")
}
buttonConfig.image = theImage
let button = UIButton(configuration: buttonConfig)
button.translatesAutoresizingMaskIntoConstraints = false
headerView.addSubview(button)
NSLayoutConstraint.activate([
button.topAnchor.constraint(equalTo: headerView.topAnchor),
button.widthAnchor.constraint(equalToConstant: 40.0),
button.heightAnchor.constraint(equalToConstant: 40.0),
button.trailingAnchor.constraint(equalTo: headerView.trailingAnchor, constant: -15.0),
])
Which produced this result:



You are not required to use the "new"
UIButton.Configurationbutton style... you can continue to use the "old" button class.However, in either case, you should be using auto-layout / constraints, rather than setting the
.frame.For example:
or, using
UIButton.Configuration:Both give this result (the yellow rectangle is "simulating" your table header view), regardless of the actual width:
Edit
Here is a complete, runnable example. Just assign
DemoTableViewControlleras the class of a table view controller:Should look like this (after I added two additional rows to section 1):