UITableview get index of each section - swift

I'm looking to get the index of each section header to be able to delete the contents within the section. But I'm unable to get the index [Below is a screenshot of my UITableview][1]
var bookings = [[String]]()
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.width, height: 100))
headerView.backgroundColor = UIColor.orange
let headerLabel = UILabel(frame: CGRect(x: 0, y: 0, width: tableView.bounds.size.width, height: 30))
headerLabel.textColor = UIColor.black
headerLabel.text = "Booking"
headerLabel.textAlignment = .center
headerView.addSubview(headerLabel)
let deleteButton: UIButton = UIButton(frame: CGRect(x:headerView.frame.size.width - 100, y:0, width:100, height:30))
deleteButton.setTitle("Delete", for: .normal)
deleteButton.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
headerView.addSubview(deleteButton)
return headerView
}
func numberOfSections(in tableView: UITableView) -> Int {
if bookings.count == 0 {
let alert = UIAlertController(title: "Warning", message: "You have no bookings" , preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Close", style: .default, handler: nil))
present(alert, animated: true, completion: nil)
}
return bookings.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let items = bookings[section]
return items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")!
let items = bookings[indexPath.section]
cell.textLabel?.text = items[indexPath.row]
return cell
}

An easy way is to use the section number as tag of the button
deleteButton.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
deleteButton.tag = section
In the action get the section index and delete the section
#objc func buttonTapped(_ sender : UIButton) {
let section = sender.tag
bookings.remove(at: section)
tableView.deleteSections([section], with: .fade)
}

You can use the following method to get the title of the section
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.section == 0 {
let sec = indexPath.section
let headrer = activityTableView.tableHeaderView?.largeContentTitle
}
}
Or
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if section == Your section{
// Your code here
}
}

If I understand you correctly, you wish to access the index of a specific section in your buttonTapped method?
One solution is to just subclass UIButton to add a section property:
class SectionDeleteButton : UIButton {
var section: Int = 0
}
You can then use this button, instead of the regular UIButton, in your header view and set the section property to the section your header belongs to. And then access this property in buttonTapped, via the sender parameter of that method.

Related

Cannot find type " " in a scope in extension file Swift 5.3

I try to use extensions in my project with independent files but I have "Cannot find type " " in a scope" when I try to instantiate UIView, UImage, UITableViewDelegate, etc. classes in my extension, how can I fix this error?
This is my code:
extension MenuView: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return titleArray.count
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = UIView()
view.backgroundColor = UIColor.white
let button = UIButton(type: .system)
button.frame = CGRect(x: 0, y: 0, width: 344, height: 50)
button.addTarget(self, action: #selector(handleExpandClose), for: .touchUpInside)
button.tag = section
view.addSubview(button)
let titleLabel = UILabel()
titleLabel.text = ((titleArray[section] as NSArray)[0] as! String)
titleLabel.font = titleLabel.font.withSize(16)
titleLabel.textColor = UIColor.black
titleLabel.frame = CGRect(x: 40, y: 20, width: 80, height: 20)
view.addSubview(titleLabel)
let icon = UIImage(named: ((titleArray[section] as NSArray)[1] as! String))
let iconImage = UIImageView(image: icon)
iconImage.frame = CGRect(x:250, y:25, width: 15, height: 10)
view.addSubview(iconImage)
return view
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 50
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if !subtitleArray[section].isExpanded {
return subtitleArray[section].names.count
}
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MenuCell", for: indexPath) as! MenuTableViewCell
cell.titleCell.text = ((subtitleArray[indexPath.section].names as NSArray)[indexPath.row] as! String)
cell.iconCell.image = UIImage.init(named: ((iconArray[indexPath.section] as NSArray)[indexPath.row] ) as! String)
return cell
}
}

Print indexpath row on label in each table view cell

In my swift code below each table view cell features a label. In that label I want to print the index path row. So in cell one the label should be 1 in cell to it should read 2. I tried to code cell.textLabel?.text = "(indexPath.row)" but that code is not complying. The code uses no storyboards all code.
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var numberOfRows = 3
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { numberOfRows }
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 118 }
var tableView = UITableView()
var selectedIndexPath = IndexPath(row: 0, section: 0)
override func viewDidLoad() {
super.viewDidLoad()
setTableVIew()
}
func setTableVIew(){
let VCframe = view.frame
let height = VCframe.height * 0.8
let widthx = VCframe.width
tableView.frame = CGRect(x: 10, y: 0, width: widthx - 20, height: height)
tableView.delegate = self
tableView.dataSource = self
view.addSubview(tableView)
tableView.register(customtv.self, forCellReuseIdentifier: "cell")
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! customtv
cell.textLabel?.text = "\(indexPath.row)"
return cell
}
}
class customtv: UITableViewCell {
lazy var backView : UIView = {
let view = UIView(frame: CGRect(x: 10, y: 6, width: self.frame.width , height: 110))
view.backgroundColor = .green
print(self.frame.width)
return view
}()
override func layoutSubviews() {
backView.clipsToBounds = true
backView.frame = CGRect(x: 0, y: 6, width: bounds.maxX , height: 110)
}
lazy var lbl : UILabel = {
let press = UILabel(frame: CGRect(x: 0, y: 3, width: 120 , height: 50))
press.backgroundColor = .yellow
press.text = String("1")
return press
}()
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(animated, animated: true)
addSubview(backView)
backView.addSubview(lbl)
}
}
You are almost there :)
You have a custom cell, so you need to set the value of custom label you created, instead of cell.textLabel?.text.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! customtv
//cell.textLabel?.text = "\(indexPath.row)" // Don't Do this.
cell.lbl.text = "\(indexPath.row)" // Do this.
return cell
}
To clarify, your cells will start with values 0, 1, 2. IndexPath.row is 0 based.

I have multiple section , each cell has a button how to know indexpath.row and indexpath.section if user clicks a button [duplicate]

This question already has answers here:
Issue Detecting Button cellForRowAt
(3 answers)
Closed 2 years ago.
Using this code i only get tag which has indexpath.row how to make a button event from it.
TaskPlayButton is my button on that i am passing indexpath.row
for single section this would have worked by now how to do on multiple section.
Is there any other way of knowing which button is clicked?
func numberOfSections(in tableView: UITableView) -> Int {
return mobileBrand.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return mobileBrand[section].modelName?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TaskCell", for: indexPath) as! TaskCell
cell.TaskName.text = mobileBrand[indexPath.section].modelName?[indexPath.row]
cell.TaskPlayButton.tag = indexPath.row
cell.TaskPlayButton.addTarget(self, action: #selector(PlayBtnClicked( _:)), for: UIButton.Event.touchUpInside)
return cell
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.width, height: 40))
view.backgroundColor = UIColor.rgb(red: 245, green: 245, blue: 245)
let lbl = UILabel(frame: CGRect(x: 15, y: 0, width: view.frame.width - 15, height: 40))
lbl.font = UIFont.systemFont(ofSize: 20)
lbl.text = mobileBrand[section].brandName
view.addSubview(lbl)
return view
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 40
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if selectedIndex == indexPath.row && isCollapse == true && selectedSection == indexPath.section{
return 240
}else{
return 60
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if selectedIndex == indexPath.row && selectedSection == indexPath.section{
if self.isCollapse == false
{
self.isCollapse = true
}else{
self.isCollapse = false
}
}else{
self.isCollapse = true
}
self.selectedIndex = indexPath.row
self.selectedSection = indexPath.section
TaskTableView.beginUpdates()
TaskTableView.endUpdates()
}
#objc func PlayBtnClicked(_ sender : UIButton)
{
print(sender.tag)
}
you can use another method like pass tag to button like this
cell.button.tag = (indexpath.section * 1000) + indexpath.row
now on your button action you can get like
let row = sender.tag%1000
let section = sender/1000
you can use closure, please look to my codes :
class YourTableViewCell: UITableViewCell {
var button: UIButton!
var buttonAction: ((UIButton) -> Void)?
#objc func buttonPressed(_ sender : UIButton)) {
self.buttonAction?(sender)
}
}
Implement it to your table view delegate :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TaskCell", for: indexPath) as! TaskCell
cell.TaskName.text = mobileBrand[indexPath.section].modelName?[indexPath.row]
cell.TaskPlayButton.tag = indexPath.row
cell.buttonAction = { sender in
// do your action
// in here, you can get indexPath.row and indexPath.section
}
cell.TaskPlayButton.addTarget(self, action: #selector(PlayBtnClicked( _:)), for: UIButton.Event.touchUpInside)
return cell
}
Hope this answer can help you :)
Pass indexPath to cell, when click the button in this cell, you could get the current indexPath
Custom a button hold a property: indexPath. Pass indexPath to the button in the method cellForRowAt. When you click the button, you could use button.indexPath to get what you want.
I just give you quick tip. It just help you on all table view in your project.
You can follow my answer here - https://stackoverflow.com/a/62481414/8135121
Here it's for you.
You can grab it by position of your button.
I explain it to you.
Make a common table view extension on your class. Just use this.
extension UITableView {
func getCellFrom(sender : UIView,completion : #escaping (UITableViewCell,IndexPath)->()){
var superview = sender.superview
while let view = superview, !(view is UITableViewCell) {
superview = view.superview
}
guard let cell = superview as? UITableViewCell else {
return
}
guard let indexPath = self.indexPath(for: cell) else {
return
}
completion(cell,indexPath)
}
}
Set target from cell in your cell for row at IndexPath function.
cell.TaskPlayButton.addTarget(self, action: #selector(PlayBtnClicked( _:)), for: UIButton.Event.touchUpInside)
Call this in PlayBtnClicked action method.
tableView.getCellFrom(sender: sender) { [weak self] (cell, indexPath) in
// Just use indexPath in here
//This closure return your cell and your button's indexPath also
}

add TestField in new row When Button Touhed swift

there is a table view and i create a button in Second cell . i handled Button Touch event with protocol .i want to add a empty text field in new row at current section Exactly below of phone number text field when add button touched but i cant handle it .
table view cell :
protocol InsertTableCellDelegate {
func insertTableCellDelegate_addrowbtn(sender:InsertTableCell1)
}
class InsertTableCell1: UITableViewCell {
var delegate : InsertTableCellDelegate?
#IBOutlet weak var tbCreateRow: UITableView!
#IBOutlet weak var txtPhoneNumber: JVFloatLabeledTextField!
override func awakeFromNib() {
super.awakeFromNib()
}
#IBAction func btn_Add_DidTouch(_ sender: Any) {
if let delegate = self.delegate
{
delegate.insertTableCellDelegate_addrowbtn(sender: self)
}
}
}
table view Delegates :
func numberOfSections(in tableView: UITableView) -> Int {
return 3
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell0 = tableView.dequeueReusableCell(withIdentifier: "InsertTableCell0") as! InsertTableCell0
return cell0
}else if indexPath.section == 1 {
//this section should handle add textfield in new row when text button touhed
let cell1 = tableView.dequeueReusableCell(withIdentifier: "InsertTableCell1") as! InsertTableCell1
cell1.delegate = self
return cell1
}else {
let cell2 = tableView.dequeueReusableCell(withIdentifier: "InsertTableCell2") as! InsertTableCell2
cell2.txtEmail.text = strEditEmail
return cell2
}
}
//protocol of button :
func insertTableCellDelegate_addrowbtn(sender: InsertTableCell1) {
print("touched")
}
numberOfRowsInSection have fixed number of cell. First you need to create a
dynamic dataSource.
sample code :
var dataSource : [Int] = Array.init(repeating: 1, count: 3)
func numberOfSections(in tableView: UITableView) -> Int {
return dataSource.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataSource[section]
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell0 = tableView.dequeueReusableCell(withIdentifier: "InsertTableCell0") as! InsertTableCell0
return cell0
}else if indexPath.section == 1 {
//this section should handle add textfield in new row when text button touhed
let cell1 = tableView.dequeueReusableCell(withIdentifier: "InsertTableCell1") as! InsertTableCell1
cell1.delegate = self
return cell1
}else {
let cell2 = tableView.dequeueReusableCell(withIdentifier: "InsertTableCell2") as! InsertTableCell2
cell2.txtEmail.text = strEditEmail
return cell2
}
}
//protocol of button :
func insertTableCellDelegate_addrowbtn(sender: InsertTableCell1) {
dataSource[1] = dataSource[1] + 1
tableView.reloadData() // or you can use beginUpdates() and endUpdates()
}
Sample of code for add new Row when click on add button in Section
//Create outlet for table view
#IBOutlet weak var currentInsetTableView: UITableView!
//Declare these variable
let reuseInsetCellIdentifier = "insertCell";
let titleSection = ["Add Phone", "Add Email"]
var arrayForCellInSection = Array<Any>()
//Add this code in viewDidLoad()
currentInsetTableView.delegate = self
currentInsetTableView.dataSource = self
currentInsetTableView.estimatedRowHeight = 200
currentInsetTableView.rowHeight = UITableView.automaticDimension
currentInsetTableView.register(UINib(nibName: "CurrentInsertTableViewCell", bundle: nil), forCellReuseIdentifier: reuseInsetCellIdentifier)
arrayForCellInSection = Array.init(repeating: 1, count: titleSection.count)
//Implematation of UITablewView Delegate
func numberOfSections(in tableView: UITableView) -> Int {
return titleSection.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrayForCellInSection[section] as! Int
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: reuseInsetCellIdentifier, for: indexPath)
as! CurrentInsertTableViewCell
cell.backgroundColor = UIColor.black
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 50
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView.init(frame: CGRect.init(x: 0, y: 0, width: tableView.frame.width, height: 50))
headerView.backgroundColor = UIColor.black
let buttonX = 10
let buttonY = 10
let buttonWidth = 30
let buttonHeight = 30
let button = UIButton(type: .system)
let imgAdd = UIImage(named: "Add")
button.setImage(imgAdd, for: .normal)
button.addTarget(self, action: #selector(buttonClickedForInsertRowInSection(sender:)), for: .touchUpInside)
button.frame = CGRect(x: buttonX, y: buttonY, width: buttonWidth, height: buttonHeight)
button.tag = section
headerView.addSubview(button)
let label = UILabel()
label.frame = CGRect.init(x: button.frame.size.width + CGFloat((2 * buttonX)), y: CGFloat(buttonY), width: headerView.frame.width - button.frame.size.width + CGFloat((3 * buttonX)), height: headerView.frame.height - CGFloat((2 * buttonY)))
label.text = titleSection[section]
label.textColor = UIColor.white
headerView.addSubview(label)
return headerView
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 50
}
//CurrentInsertTableViewCell Desing
//Final Result: When we press two times on first section add button & one times on second section add button

Put a UIButton in tableView

I made a code for added a array of UIView in my TableView, but when I add them, it doesn't show them row by row while I made a loop for it to add each item in my TableView but it adds them one above the other, another solution?
my view controller :
class mainViewController: UIViewController {
private var myArray: [UIView] = []
private var myTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
let barHeight: CGFloat = UIApplication.shared.statusBarFrame.size.height
let displayWidth: CGFloat = self.view.frame.width
let displayHeight: CGFloat = self.view.frame.height
myTableView = UITableView(frame: CGRect(x: 50, y: barHeight, width: displayWidth, height: displayHeight - barHeight))
myTableView.register(UITableViewCell.self, forCellReuseIdentifier: "MyCell")
myTableView.dataSource = self
myTableView.delegate = self
self.view.addSubview(myTableView)
let DoneBut: UIButton = UIButton(frame: CGRect(x: 50, y: 0, width: 150, height: 50))
DoneBut.setTitle("Done", for: .normal)
DoneBut.backgroundColor = UIColor.blue
let DoneBut2: UIButton = UIButton(frame: CGRect(x: 50, y: 0, width: 50, height: 50))
DoneBut2.setTitle("Done2", for: .normal)
DoneBut2.backgroundColor = UIColor.blue
let view1 = UIView()
view1.addSubview(DoneBut)
myArray.append(view1)
let view2 = UIView()
view2.addSubview(DoneBut2)
myArray.append(view2)
}
}
extension mainViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath:
IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier:
"MyCell", for: indexPath as IndexPath)
for array in myArray {
cell.contentView.addSubview(array)
}
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection
section: Int) -> Int {
return myArray.count
}
}
extension mainViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath:
IndexPath) {
print("Num: \(indexPath.row)")
print("Value: \(myArray[indexPath.row])")
}
}
Your issue is that each time the cellForRowAt function is asking for a cell, you are looping through ALL the views and adding them to each cell. Instead you should be indexing in it using the indexPath. See the following:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath as IndexPath)
// check if there is a view at the indexPath
if indexPath.row < myArray.count {
// there is a view, add it to the cells contentView
cell.contentView.addSubview(myArray[indexPath.row])
} else {
print("no view at index")
}
return cell
}