I have an Expanded TableView, with HeaderView containing a checkBox, a label and a radioButton.
CheckBoxes can have multiple selection. But radioButton has only single selection. If another radio-button is selected, then previously selected button gets deselected in tableView
My problem is, whenever I select a radio-button at section 0, then radio-button at section 8 and 16 also get selected. Upon scrolling the radio-button changes it's state. Any radio-button for any section gets selected. I am aware it is due to the cell reuse property of the tableView, But I am not getting how to solve this. I have referred to numerous solutions here on SO, but none seemed to work. This issue is really troublesome for me, because of which I am not able to proceed further. Kindly guide me if wrong or if I am missing something. Help much appreciated. Thank you!
Here is my code for HeaderView of tableView:
import UIKit
import M13Checkbox
protocol HeaderViewDelegate {
func toggleHeader(header : HeaderView, section : Int)
}
protocol CustomHeaderDelegate: class {
func didTapButton(in section: Int, headerView : HeaderView)
}
class HeaderView: UITableViewHeaderFooterView {
#IBOutlet weak var stateCheckBox: M13Checkbox!
#IBOutlet weak var stateNameLabel: UILabel!
#IBOutlet weak var favouriteState: M13Checkbox!
var delegate : HeaderViewDelegate?
weak var delegateHeader: CustomHeaderDelegate?
var sectionNumber : Int!
var section : Int!
var radioButtonSelected : Bool = false {
didSet {
if radioButtonSelected {
favouriteState.checkState = .checked
}else{
favoriteState.checkState = .unchecked
}
}
}
override func awakeFromNib() {
stateCheckBox.boxType = .square
stateCheckBox = .bounce(.fill)
favouriteState.boxType = .circle
favouriteState.setMarkType(markType: .radio, animated: true)
favouriteState.stateChangeAnimation = .bounce(.stroke)
}
override init(reuseIdentifier: String?) {
super.init(reuseIdentifier: reuseIdentifier)
self.addGestureRecognizer(UITapGestureRecognizer(target : self, action: #selector(selectHeaderView)))
}
required init?(coder aDecoder: NSCoder) {
super.init(coder : aDecoder)
self.addGestureRecognizer(UITapGestureRecognizer(target : self, action: #selector(selectHeaderView)))
}
func selectHeaderView(gesture : UITapGestureRecognizer) {
let cell = gesture.view as! HeaderView
delegate?.toggleHeader(header: self, section: cell.section)
}
func customInit(titleLabel : String, section : Int, delegate : HeaderViewDelegate) {
self.stateNameLabel.text = titleLabel
self.section = section
self.delegate = delegate
}
#IBAction func selectPrimaryCondition(_ sender: M13Checkbox) {
// get section when favourite state radioButton is selected
delegateHeader?.didTapButton(in: sectionNumber, headerView : self)
}
override func prepareForReuse() {
// What do do hereā¦??
}
}
Here is my ViewController class:
func numberOfSections(in tableView: UITableView) -> Int {
return states.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return states[section].cities.count
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 50.0
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if (states[indexPath.section].expanded) {
return 44
}else{
return 0.0
}
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerCell = tableView.dequeueReusableHeaderFooterView(withIdentifier: "headerviewcell") as! HeaderView
var list = states[section]
headerCell.customInit(titleLabel: list.stateName, section: section, delegate: self)
return headerCell
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "subcells") as! CollapsibleCell
cell.selectionStyle = .none
cell.textLabel?.text = states[indexPath.section].cities[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// works for headers or cell??
}
func toggleHeader(header : HeaderView, section : Int){
states[section].expanded = !states[section].expanded
for i in 0 ..< states[section].cites.count {
tableView.reloadRows(at: [IndexPath(row: i, section: section)], with: .automatic)
}
}
extension ViewController: HeaderDelegate {
func didTapButton(in section: Int, headerView : HeaderView) {
print("\(section)")
}
}
Expected Output:
What I am getting:
Related
I have a storyboard with two buttons, each one with target to another storyboard with a TableView but different segue identifier.
Right now I populate my data source through a two dimension array
var dataArray = [["a", "b", "c"], ["menu 1", "menu 2", "menu 3"]]
What I would like to do is based on the button selection hide a TableView section.
Example:
Selected button 1 hide section 2 on my TableView.
&
Selected button 2 hide section 1 on my TableView.
My data source extension looks like this
extension ViewControllerTwo: UITableViewDataSource{
func numberOfSections(in tableView: UITableView) -> Int {
return dataArray.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if section == 0{
return "Section 1"
}
return "Section 2"
}
func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
if section == 0{
return "Number of items in section 1 is \(dataArray[0].count)"
}
return "Number of items in section 2 is \(dataArray[1].count)"
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataArray[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "singleCell")
if cell == nil{
cell = UITableViewCell(style: .default, reuseIdentifier: "singleCell")
cell?.accessoryType = .detailButton
}
cell!.textLabel?.text = dataArray[indexPath.section][indexPath.row]
return cell!
}
}
The two viewControllers are named as follow
"ViewController"
"ViewControllerTwo"
Think of the segues identifiers named as follow
"segueItemsOption" for button 1
"segueMenuOption" for button 2
Edit
View Controller Code.
Haven't really modified anything as segue automatically displays the next VC.
import UIKit
class ViewController: UIViewController {
// MARK: Outlets
#IBOutlet weak var itemsButton: UIButton!
#IBOutlet weak var menuButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Buttons Rounded Corner
itemsButton.round()
itemsButton.round()
}
// MARK: Button Actions
#IBAction func itesmButtonAction(_ sender: Any) {
createVolumes.shine()
}
#IBAction func menuButtonAction(_ sender: Any) {
listVolumes.shine()
}
To achieve what you want you can try following:
Create an enum:
enum ShowCase: Int{
case items, menu
var headerTitle: String{
switch self {
case .items:
return "Section 1"
case .menu:
return "Section 2"
}
}
static func createFromSegueIdentifier(_ str: String) -> ShowCase{
str == "segueItemsOption" ? .items : .menu
}
}
In you ViewController add:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let vc = segue.destination as? ViewControllerTwo, let identifier = segue.identifier else{
return
}
vc.showCase = ShowCase.createFromSegueIdentifier(identifier)
}
in ViewcontrollerTwo add an implicitly unwrapped var:
var showCase: ShowCase!
and the extension should look like:
extension ViewControllerTwo: UITableViewDataSource{
func numberOfSections(in tableView: UITableView) -> Int {
// return only one section
1
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
showCase.headerTitle
}
func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
"Number of items in \(showCase.headerTitle.lowercased()) is \(dataArray[showCase.rawValue].count)"
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataArray[showCase.rawValue].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "singleCell")
if cell == nil{
cell = UITableViewCell(style: .default, reuseIdentifier: "singleCell")
cell?.accessoryType = .detailButton
}
cell!.textLabel?.text = dataArray[showCase.rawValue][indexPath.row]
return cell!
}
}
Ugh, try creating an if condition for each segue and .isHidden property.
That works 100% fam
*hi I have a problem if anyone can guide me to the appropriate solution for this one it will be awesome....
I have a tableview with list items that can be selected (like a checkbox) also a textview that when I write there I don't won't the text deleted (for the user) every time It scrolls.
my custom cell class - >
class ReportIssueTableViewCell: UITableViewCell, ReusableView, NibLoadableView {
//MARK: Properties
#IBOutlet private weak var lblTitleIssue: UILabel!
#IBOutlet private weak var imgCircleCheck: UIImageView!
#IBOutlet private weak var textView: WSTextView!
#IBOutlet private weak var stackView: UIStackView!
#IBOutlet private weak var sepratorView: UIView!
private var reportIssue: ReportIssue?
private var textContent = ""
private var lastIndex = false
//MARK: Methods
func setupDataForCell(isSelected: Bool, reportIssues: ReportIssue, lastIndex: Bool) {
self.isSelected = isSelected
self.reportIssue = reportIssues
self.lastIndex = lastIndex
updateUI()
}
override func prepareForReuse() {
super.prepareForReuse()
textView.text = textContent
imgCircleCheck.image = nil
}
func updateUI() {
guard let reportIssue = reportIssue else { return }
lblTitleIssue.text = reportIssue.name
updateImageUI()
updateTextView()
updateTitleUI()
}
func sepratorView(hide: Bool, lastIndex: Bool) {
sepratorView.isHidden = (lastIndex && hide)
}
//MARK: Private Methods
private func updateTitleUI() {
let font = lblTitleIssue.font.pointSize
lblTitleIssue.font = isSelected ? SharedFonts.latoBold.ofSize(font) : SharedFonts.latoRegular.ofSize(font)
}
private func updateImageUI() {
imgCircleCheck.image = isSelected ? R.image.iconCircleCheckFull() : SharedAssets.iconsCircle()
}
private func updateTextView() {
textView.isHidden = !(lastIndex && isSelected)
}
}
also my view controller class and the tableview delegate & data source...
extension ReportIssueViewController: UITableViewDelegate , UITableViewDataSource {
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
if section == 0 {
let footerView = UIView()
footerView.backgroundColor = SharedColors.woodspoon_extra_light_gray()
return footerView
}else {
return UIView()
}
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 8
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
guard let name = viewModel.reportTopics?[section].name else { return nil }
let header = SectionTitleHeaderView(textDescriptor: .init(text: name, appearance: .init(color: SharedColors.woodspoon_black(), font: SharedFonts.latoBlack.ofSize(18))))
return header
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if #available(iOS 15.0, *) {
tableView.sectionHeaderTopPadding = 0
} else {
//Fallback on earlier versions
}
return UITableView.automaticDimension
}
func numberOfSections(in tableView: UITableView) -> Int {
return viewModel.reportTopics?.count ?? 0
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel.reportTopics?[section].reportIssues?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: ReportIssueTableViewCell = tableView.dequeueReusableCell(for: indexPath)
if let issue = viewModel.reportTopics?[indexPath.section].reportIssues?[indexPath.row] {
let countIssues = viewModel.reportTopics?[indexPath.section].reportIssues?.count ?? 0
let lastIssue = countIssues - 1 == indexPath.row
let isSelected = tableView.indexPathsForSelectedRows?.contains(where: { $0.section == indexPath.section && $0.row == indexPath.row })
//remove seperator from last cell in each section
if isSelected == isSelected {
cell.sepratorView(hide: true ,lastIndex: lastIssue)
}
cell.setupDataForCell(isSelected: isSelected ?? false, reportIssues: issue, lastIndex: lastIssue)
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
cellPressed(indexPath: indexPath)
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
cellPressed(indexPath: indexPath)
}
private func cellPressed(indexPath: IndexPath) {
guard let cell = tableView.cellForRow(at: indexPath) as? ReportIssueTableViewCell else { return }
tableView.beginUpdates()
cell.updateUI()
tableView.endUpdates()
}*
I think it happens because the reuse of cells.
Your problem starts here:
isSelected = tableView.indexPathsForSelectedRows?.contains(where: {
$0.section == indexPath.section && $0.row == indexPath.row
})
Add an isSelected value to the model used to populate the cell and get it from your viewModel by adding an isSelected func that return bool value and get it inside cellForRowAt IndexPath.
Something like this:
func isSelected(by indexPath: IndexPath) { }
And remember to update the model (via viewModel) when a cell was selected.
I have fix make the cell to cliptobounds in the table view and also assign constraints to fix the table position and height.
Below are some parts of my code.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if hiddenRow.contains(indexPath.row) || hiddenRow2.contains(indexPath.row){
rowHeight.append(300)
return 300 //Expanded
}
else{
rowHeight.append(120)
return 120 //Not Expanded
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "med_reusable_cell", for: indexPath as IndexPath) as! MedListTableViewCell
cell.backgroundColor = TRANSPARENT
cell.layer.cornerRadius = DEFAULT_CORNER_RADIUS
active_table_height.constant = self.view.frame.size.height * 11/36
expired_table_height.constant = self.view.frame.size.height * 11/36
cell overflow
The different between my code and others are
This is an expendable view cell which the height will be change based whether the cell is expended
I use a reusable cell for two tables.
How can I solve this?
You can achieve this by adding a header to each cell, then when you'll click it, reload the table view with the opened cell look at this example :
DataModel :
struct DataItem {
var isExpand: Bool
var title: String
var value:String
init(isExpand:Bool = false, title:String, value:String) {
self.isExpand = isExpand
self.title = title
self.value = value
}
}
Custom Header witch will listen to events :
protocol CustomHeaderViewDelegate: AnyObject {
func headerViewTap(_ section: Int)
}
class CustomHeaderView: UITableViewHeaderFooterView {
weak var delegate: CustomHeaderViewDelegate?
var sectionNumber: Int?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
let gesture = UITapGestureRecognizer(target: self, action: #selector(CustomHeaderView.tableViewSectionTapped(_:)))
self.addGestureRecognizer(gesture)
}
#objc func tableViewSectionTapped(_ gesture: UIGestureRecognizer) {
if let sectionNumber = sectionNumber{
delegate?.headerViewTap(sectionNumber)
}
}
}
TableView and Custom Header delegates
extension ViewController : UITableViewDelegate, UITableViewDataSource{
//The number of sections fits the number of cells, the current list is an array of DataObject, holding a title and a content.
func numberOfSections(in tableView: UITableView) -> Int {
return self.currentList.count
}
//Each section(group of cells) contains one row
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as UITableViewCell
return cell
}
//update heights for row if the header has been taped
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let isExpanded = self.currentList[indexPath.section].isExpand
if isExpanded {
return UITableView.automaticDimension
}
return 0
}
//update the estimatedHeightForRowAt if the hader has been taped
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
let isExpanded = self.currentList[indexPath.section].isExpand
if isExpanded{
return UITableView.automaticDimension
}
return 0
}
//returns a custom header
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "Header") as! CustomHeaderView
return headerView
}
}
extension ViewController : CustomeHeaderViewDelegate{
func headerViewTap(_ section: Int) {
selectedItem = self.currentList[section]
let output = self.currentList.map({ (item:DataItem) -> DataItem in
var result = item
if result.title == self.selectedItem?.title{
result.isExpand = !result.isExpand
}
return result
})
self.currentList = output
self.tableView.reloadSections(IndexSet(integer: section), with: UITableView.RowAnimation.automatic)
self.tableView.endUpdates()
}
}
I must implemented TableView with Header and Footer view. I have all implemented but when the tableView is created, footer and header stay still in my screen.
And i want that my Footer will be on the bottom on last cell in table view, and she will appear when I scroll down on bottom of tableview.
So as like a Header, When i will by scrolling down header stay Top on table view. Anyone can help me ?
My code:
Controllr which contains tableView:
#IBOutlet weak var tableView: UITableView! {
didSet {
let headerNib = UINib(nibName: SearchingHeader.headerID, bundle: nil)
tableView.register(headerNib, forHeaderFooterViewReuseIdentifier: SearchingHeader.headerID)
let cellNib = UINib(nibName: SearchingResultTableViewCell.cellId, bundle: nil)
tableView.register(cellNib, forCellReuseIdentifier: SearchingResultTableViewCell.cellId)
let footerNib = UINib(nibName: SearchingFooter.footerId, bundle: nil)
tableView.register(footerNib, forHeaderFooterViewReuseIdentifier: SearchingFooter.footerId)
}
}
extension SearchingViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: SearchingHeader.headerID) as! SearchingHeader
header.objectForSearch = objectOfSearch
header.addressOnSearch = addressOfSearch
return header.contentView
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 132
}
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footer = tableView.dequeueReusableHeaderFooterView(withIdentifier: SearchingFooter.footerId) as! SearchingFooter
return footer.contentView
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 243
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: SearchingResultTableViewCell.cellId, for: indexPath) as! SearchingResultTableViewCell
return cell
}
Header xib:
class SearchingHeader: UITableViewHeaderFooterView {
/// OUTLETS ///
#IBOutlet weak var mapButton: EnhancedButton! {
didSet {
mapButton.setImage(Asset.Icons.icoMap.image, for: .normal)
mapButton.imageColor = UIColor.white
mapButton.cornerRadius = 5
mapButton.backgroundColor = ColorName.mainTurquoise.color
}
}
#IBOutlet weak var objectOfSearchingTextField: LocalizedTextField!
#IBOutlet weak var searchIconImageView: EnhancedImageView! {
didSet {
searchIconImageView.imageColor = ColorName.mainOrange.color
}
}
#IBOutlet weak var collectionView: UICollectionView! {
didSet {
collectionView.layer.backgroundColor = ColorName.mainGrey.color.cgColor
let cellNib = UINib(nibName: SearchFilterCollectionViewCell.cellId , bundle: nil)
collectionView.register(cellNib, forCellWithReuseIdentifier: SearchFilterCollectionViewCell.cellId )
}
}
/// PROPERTIES ///
static var headerID: String = "Header"
var objectForSearch: String? {
didSet {
setSearchParameters()
}
}
var addressOnSearch: String? {
didSet {
setSearchParameters()
}
}
/// METHODS
override func awakeFromNib() {
super.awakeFromNib()
setUpView()
}
Footer is created in the same way.
I have a problem with my TableView. After adding a section footer, I realized that it moves when I swipe-to-delete.
I have created a minimal project with just this function to show the problem I face.
This is the result I get
I have two TableViewCell : DetailCell
import UIKit
class DetailCell: UITableViewCell {
#IBOutlet weak var myTextLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
and HeaderFooterCell
import UIKit
class HeaderFooterCell: UITableViewCell {
#IBOutlet weak var thisTextLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
This is the tableViewController
import UIKit
class TableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
let statusBarHeight = UIApplication.shared.statusBarFrame.height
self.tableView.contentInset = UIEdgeInsetsMake(statusBarHeight, 0.0, 0.0, 0.0)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "myTableViewCell", for: indexPath) as! DetailCell
switch indexPath.row {
case 0: cell.myTextLabel?.text = "one - one - one - one"
case 1: cell.myTextLabel?.text = "two - two - two - two"
case 2: cell.myTextLabel?.text = "three - three - three - three"
case 3: cell.myTextLabel?.text = "four - four - four - four"
case 4: cell.myTextLabel?.text = "five - five - five - five"
default: break
}
return cell
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 44
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cell = tableView.dequeueReusableCell(withIdentifier: "headerOrFooterCell") as! HeaderFooterCell
cell.thisTextLabel.text = "Less"
return cell
}
override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 44
}
override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let cell = tableView.dequeueReusableCell(withIdentifier: "headerOrFooterCell") as! HeaderFooterCell
cell.thisTextLabel.text = "More"
return cell
}
// MARK: RowAction for DELETE and MODIFY
override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let delete = UITableViewRowAction(style: .destructive, title: "Delete") { (action, indexPath) in
print ("Delete")
}
let modify = UITableViewRowAction(style: .normal, title: "Modify") { (action, indexPath) in
print("Modify")
}
return [delete, modify]
}
}
Did I make a mistake, or is there a way to 'block' horizontally the header and Footer?
Change type of header and footer to UITableViewHeaderFooterView and then use .dequeueReusableHeaderFooterView(withIdentifier: "headerOrFooterCell") tableView method. Don't forget to register nibs. I tested code below and it works without problem you were writing about.
import UIKit
class DetailCell: UITableViewCell {
#IBOutlet weak var myTextLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
}
class HeaderFooterCell: UITableViewHeaderFooterView {
#IBOutlet weak var thisTextLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
}
class TableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
let statusBarHeight = UIApplication.shared.statusBarFrame.height
self.tableView.contentInset = UIEdgeInsetsMake(statusBarHeight, 0.0, 0.0, 0.0)
self.tableView.register(UINib(nibName:"DetailCell", bundle: nil), forCellReuseIdentifier: "myTableViewCell")
self.tableView.register(UINib(nibName:"HeaderFooterCell", bundle: nil), forHeaderFooterViewReuseIdentifier: "headerOrFooterCell")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "myTableViewCell", for: indexPath) as! DetailCell
switch indexPath.row {
case 0: cell.myTextLabel?.text = "one - one - one - one"
case 1: cell.myTextLabel?.text = "two - two - two - two"
case 2: cell.myTextLabel?.text = "three - three - three - three"
case 3: cell.myTextLabel?.text = "four - four - four - four"
case 4: cell.myTextLabel?.text = "five - five - five - five"
default: break
}
return cell
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 44
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cell = tableView.dequeueReusableHeaderFooterView(withIdentifier: "headerOrFooterCell") as! HeaderFooterCell
cell.thisTextLabel.text = "Less"
return cell
}
override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 44
}
override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let cell = tableView.dequeueReusableHeaderFooterView(withIdentifier: "headerOrFooterCell") as! HeaderFooterCell
cell.thisTextLabel.text = "More"
return cell
}
// MARK: RowAction for DELETE and MODIFY
override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let delete = UITableViewRowAction(style: .destructive, title: "Delete") { (action, indexPath) in
print ("Delete")
}
let modify = UITableViewRowAction(style: .normal, title: "Modify") { (action, indexPath) in
print("Modify")
}
return [delete, modify]
}
}