Add Text Label and Button to dynamic tableview cell programmatically with Swift - swift

I have a dynamic tableview and a prototype cell which displays an array. My questions is how would I add a button which displays different names on each cell to the Left side of the cell and then a label to the right side displaying the array info. Thanks! :D
So imagine this is the cell below:
Left side:Button(array info) <-------------------> Right side:TextLabel(array info)

You can implement like this
let titleArray = ["a", "b", "c"]
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 50
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//return no.of cell do you want
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cellHeight = tableView(self.tableView, heightForRowAtIndexPath: NSIndexPath(forRow: indexPath.row, inSection: indexPath.section))
var cell = CustomCell(frame: CGRectMake(0, 0, self.view.frame.width, cellHeight), title: titleArray[indexPath.row])
cell.cellLabel.text = //labelText
cell.cellButton.addTarget(self, action: "buttonPressed:", forControlEvents: UIControlEvents.TouchUpInside)
return cell
}
class CustomCell: UITableViewCell {
var cellButton: UIButton!
var cellLabel: UILabel!
init(frame: CGRect, title: String) {
super.init(style: UITableViewCellStyle.Default, reuseIdentifier: "cell")
cellLabel= UILabel(frame: CGRectMake(self.frame.width - 100, 10, 100.0, 40))
cellLabel.textColor = UIColor.blackColor()
cellLabel.font = //set font here
cellButton = UIButton(frame: CGRectMake(5, 5, 50, 30))
cellButton.setTitle(title, forState: UIControlState.Normal)
addSubview(cellLabel)
addSubview(cellButton)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
}

I got the solution for your question, please follow the below steps
var data = ["iPad", "iPhone", "iWatch", "iPod", "iMac"]
var buttonData = ["US","China","London","Canada","Japan"];
//UITableViewDataSource Methods
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
{
return 80
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return data.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
var cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
var label = UILabel(frame: CGRectMake(280.0, 14.0, 100.0, 30.0))
label.text = data[indexPath.row]
label.tag = indexPath.row
cell.contentView.addSubview(label)
let btn = UIButton.buttonWithType(UIButtonType.Custom) as UIButton
btn.backgroundColor = UIColor.greenColor()
btn.setTitle(buttonData[indexPath.row], forState: UIControlState.Normal)
btn.frame = CGRectMake(0, 5, 80, 40)
btn.addTarget(self, action: "buttonPressed:", forControlEvents: UIControlEvents.TouchUpInside)
btn.tag = indexPath.row
cell.contentView.addSubview(btn)
return cell
}
//Button Action is
func buttonPressed(sender:UIButton!)
{
let buttonRow = sender.tag
println("button is Pressed")
println("Clicked Button Row is",buttonRow)
}

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.

UITableview get index of each section

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.

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
}

How to add different accessories(or subviews) for each cell in swift?

I made 4 identical cells with subviews by using UITableViewCell subclass 'FruitTableViewCell' class.
FruitTableViewCell.swift
class FruitTableViewCell: UITableViewCell, UITextFieldDelegate {
var fruitsTextField = UITextField()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.contentView.addSubview(fruitsTextField)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
fruitsTextField.frame = CGRect(x: 100, y: 7.5, width: 50, height: 30)
fruitsTextField.backgroundColor = UIColor.darkGray
fruitsTextField.delegate = self
}
}
TableViewController.swift
class TableViewController: UITableViewController, UITextFieldDelegate {
let fruitsComponents: [String] = ["Apple", "Banana", "Grape", "Pear"]
let cellReuseidentifier = "cell"
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(FruitTableViewCell.self, forCellReuseIdentifier: cellReuseidentifier)
}
override func numberOfSections(in tableView: UITableView) -> Int {
sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return fruitsComponents.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseidentifier, for: indexPath) as! FruitTableViewCell
cell.textLabel?.text = fruitsComponents[indexPath.row]
return cell
}
}
It works well.
But in fact, I want to add different accessories(or subviews) for each cell. Row 0 for UITextField, Row 1 for UILabel, Row 2 for Stepper, Row 3 for UILabel, ... and so on.
So I made the other UITableViewCell subclass 'AnotherFruitTableViewCell' class to use.
And I tried by using 'if' statement.
revised TableViewController.swift
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseidentifier, for: indexPath) as! FruitTableViewCell
cell.textLabel?.text = fruitsComponents[indexPath.row]
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseidentifier, for: indexPath) as! AnotherFruitTableViewCell
cell.textLabel?.text = fruitsComponents[indexPath.row]
return cell
}
But the message 'could not cast value of type' poped up.
Because of this code, I think.
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(FruitTableViewCell.self, forCellReuseIdentifier: cellReuseidentifier)
}
And fundamentally, I think 'if' statement is not a good way to add different accessories for each cells.
How can I add different accessories(or subviews) for each cell?
You registered your FruitTableViewCell but not registered AnotherFruitTableViewCell