I'm quite new to Swift and I would like to know what is the easiest and simplest way for me to add in 10 buttons to 10 of my cell rows in my TableViewController.
P.S: It would be nice if the 10 buttons perform differently instead of duplicate.
import UIKit
import FirebaseDatabase
var ref: DatabaseReference?
var databaseHandle: DatabaseHandle?
var postData = [String]()
class TableViewController5: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
ref = Database.database().reference() //set the firebase reference
// Retrieve the post and listen for changes
databaseHandle = ref?.child("Posts3").observe(.value, with: { (snapshot) in
postData.removeAll()
for child in snapshot.children {
let snap = child as! DataSnapshot
let key = snap.key
postData.append(key)
}
self.tableView.reloadData()
})
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return postData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.font = UIFont.init(name: "Helvetica", size: 23)
cell.textLabel?.text = postData[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
return 80
}
}
From what I can understand, you should use prototype cell and add an IBAction in the cell and in that cell you should perform the segue and pass whatever data you need to customise the page you load.
In your tableView(_:cellForRowAt:) method, you can set a tag for the button.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? prototypeCell
cell.voteButton.tag = indexPath.row
return cell
}
Then in your cell's class, in the IBAction I mentioned earlier, check for the tag and set the data to pass accordingly.
Then in your prepareForSegue:sender: method, just pass the data you want to pass to the next view controller and all should work fine.
Check if it helps You
//Common cell Variable
var cell = UITableViewCell()
//UIButton commonly Declared
var acceptRequest = UIButton()
var declineRequest = UIButton()
My TableView Cell contains two button as shown Accept & Decline
In my tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) I added Handlers for button
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//Cell for dequeuing
cell = self.RequestListTableView.dequeueReusableCell(withIdentifier: "Cell")!
//Used Tags here
//You can Make use of TableViewCell class here and Access Buttons from there
acceptRequest = cell.viewWithTag(4) as! UIButton
//Adding action Handlers for UIbuttons
self.acceptRequest.addTarget(self, action: #selector(RequestListView.AcceptRequest(sender:)), for: .touchUpInside)
return cell
}
my Button handler
func AcceptRequest (sender: UIButton) {
//Dequeue cell with identifier can be ignored
cell = self.RequestListTableView.dequeueReusableCell(withIdentifier: "Cell")!
//Get button position from TableView : Required
let buttonPosition : CGPoint = sender.convert(CGPoint.zero, to: self.RequestListTableView)
//Get index Path of selected Cell from TableView
//Returns Table Cell index same as didSelect
let indexPath : IndexPath = self.RequestListTableView.indexPathForRow(at: buttonPosition)!
//Can be used if you need to update a view
cell = self.RequestListTableView.cellForRow(at: indexPath)!
//Now time to access using index Path
cell.textLabel.text = array[indexPath.row] //Example
}
Can use this Procedure for even single Button or for multiple buttons too
In case if you have more than one button in one cell, this will help you
Related
I want to add spacing between rows and set the header
here my code is -
#IBOutlet weak var sideMenu: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arr.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! TownTalkTableViewCell
cell.logo.setImage(arr[indexPath.row]["icon"] as? UIImage, for: .normal)
cell.grupName.text = array[indexPath.row]["groupname"] as? String
return cell
First Add tableview Delegate and Data Source for both tableview in storyboard by taping control+draging into viewcontroller
Then use the same delegate function to access sidemenu tableview.
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var sideMenu: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableview == sideMenu{
return 2
}else{
//this is for tableView
return 3
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableview == sideMenu{
//use slide menu tableview cell
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! TownTalkTableViewCell
cell.grupImage.image = array[indexPath.row]["groupImage"] as? UIImage
cell.grupName.text = array[indexPath.row]["groupname"] as? String
return cell
}else{
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! TownTalkTableViewCell
cell.grupImage.image = array[indexPath.row]["groupImage"] as? UIImage
cell.grupName.text = array[indexPath.row]["groupname"] as? String
return cell
}
}
2 ways.
make the view controller data source & delegate for both the tableviews & in the methods add the below check.
if tableview === self.tableview {
//its for table view
return ...
}
// else its for side menu
return ...
Create a separate class (Call it SideMenuTableViewHelper or something) for SideMenu tableView datasource & delegate.
First one is simpler, 2nd one is cleaner for datasource, messier for handling delegate (did select row) methods as they will most likely be triggering code in view controller (which can be done via View controller acting as custom delegate to the SideMenuTableViewHelper). For a beginner, I reckon go with (1).
I take tableView and two different cell.xib files , I want to display when i click cell1 then i should display cell2 data.
class TableView: UIViewController,UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var array1 = ["Click1","Click2"]
var array2 = [[ "one","two","Three"],["Four","Five"]]
var selectedArray = [String]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: "MainCell", bundle: nil) , forCellReuseIdentifier: "MainCell")//This is used to add xib file with identifier
tableView.register(UINib(nibName: "SecondCell", bundle: nil) , forCellReuseIdentifier: "SecondCell")
}
//MARK:DataSource Methods
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return array1.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCell(withIdentifier: "MainCell") as! MainCell
cell.textLabel?.text = array1[indexPath.row]
return cell
}
//MARK: tableViewDelegate Method
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = self.tableView.dequeueReusableCell(withIdentifier: "SecondCell") as! SecondCell
selectedArray = array2[indexPath.row]
cell.textLabel?.text = selectedArray[indexPath.row]
}
}
Tell how can i do that if i press first cell it should show 2nd cell values as per indexPath.row
I think you want to achieve expandable cells. You can use the header cell for this one.
You might want to read this:
Hope this helps!
For example, you can add a flag which indicates whether the first cell was tapped.
var wasFirstCellTapped = false
Then numberOfRowsInSection depends on this flag:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return wasFirstCellTapped ? array1.count : 1
}
In didSelectRowAt:indexPath set this flag to true. And perform tableView changes. The simplest way is to call tableView.reloadData(). But you can animate this using insertRowsAtIndexPaths
var allCellsArray = ["Click1","Click2"]
var displayingCellsArray = ["Click1"]
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return displayingCellsArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell: UITableViewCell!
if displayingCellsArray[indexPath.row] == "Click1" {
cell = self.tableView.dequeueReusableCell(withIdentifier: "MainCell") as! MainCell
}else {
cell = self.tableView.dequeueReusableCell(withIdentifier: "SecondCell") as! SecondCell
}
cell.textLabel?.text = displayingCellsArray[indexPath.row]
return cell
}
//MARK: tableViewDelegate Method
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let data = displayingCellsArray[indexPath.row]
//Below logic will show (Cell2 if Cell1 is clicked and hide Cell1)
// (and show Cell1 if clicked Cell2 and hide Cell2)
if data == "Click1" {
displayingCellsArray = [allCellsArray.last!]
}else {
displayingCellsArray = [allCellsArray.first!]
}
tableView.reloadData()
}
You should handle such logic in a separate datasource array by adding/removing that sort of data from this array which shows particular cells.
E.g
In your case you have two values in array Click1 & Click2
Click1 shows MainCell & Click2 shows SecondCell
So first add Click1 in your array and when this cell is tapped simply add Click2 in your array and reload. If you want to remove MainCell when SecondCell is displaying then while adding Click2 simply remove Click1
You can expand the second cell on click of first cell..
Refer this example to expand and collapse the cells
https://github.com/jonasman/JNExpandableTableView
I'm using tableView cell with button name of delete and I want to delete my JSON data from tableView cell I need to so That JSON ID to delete the JSON data from my Tableview. I'm using to get the JSON ID for that indexPath in didSelect row function. but the problem is I can't get JSON Id from that indexPath without pressing the row.
var selectedList: JSONList?
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedList = JSONList[indexPath.row]
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = Tableview.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? TableviewCell
cell?.Numbers.text = JSONList[indexPath.row].Number
cell?.Trash.addTarget(self, action: #selector(Deleting), for: .touchUpInside)
cell?.selectionStyle = .none
return cell!
}
//here is my delete function calling
func Deleting() {
let selectedListObj = selectedList
print(selectedListObj!.id)
}
First of all set a tag to the button which it will be in your case the
row of the IndexPath, add this code in cellForRowAt:
cell?.Trash.addTarget(self, action: #selector(deleting(_:)), for:
.touchUpInside)
cell?.Trash.tag = indexPath.row
You need to modify the deleting() function to be #objc since selectors
after swift 3+ are a must to add that and add the button as param into it:
#objc private func deleting(_ button:UIButton){
// here you got the object
let selectedObject = JSONList[button.tag]
}
use closure to get the tapped buttons cells indexpath.
update the table view cell with ibaction and call the closure whenever tapping on trash button.
class FakeTableCell: UITableViewCell{
var selectedCell: ((UITableViewCell) -> ())?
#IBAction func trashButtonTapped(){
selectedCell?(self)
}
}
then we can get the indexpath of the cell in cell for row for indexpath as follows
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = FakeTableCell()
cell.selectedCell = { selectedCell in
if let ip = tableView.indexPathForRow(at: selectedCell.center){
self.deleteData(with: ip.row)
}
}
return cell
}
func deleteData(with row: Int){
// get the object by JSONList[row]
let item = JSONList[row]
// perform deletion
}
I have
["06:58"]
["07:13", "07:38", "07:53"]
["08:13", "08:38", "08:53"]
["09:13", "09:33", "09:53"]
and I want to show it in tableView as in picture:
every element - it's UILabel, I created class TimeViewCell: UITableViewCell where have property var labels = [UILabel]() but I don't know how to push data from my array in my function:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellTime", for: indexPath) as! TimeViewCell
let showHour = self.infoWripper.sorted(by: { $0.hour < $1.hour })
cell.labelTime.text = showHour[indexPath.row].showHour()
for data in showHour {
print(data.showFullTime()) //here you see my example of data in console
}
return cell
}
I would add a UIStackView to your UITableViewCell. You can add the labels with the text to the UIStackView.
I wrapped your data into an array.
let tableViewData = [["06:58"],
["07:13", "07:38", "07:53"],
["08:13", "08:38", "08:53"],
["09:13", "09:33", "09:53"]]
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellTime", for: indexPath) as! TimeViewCell
cell.configure(data: tableViewData[indexPath.row])
return cell
}
Then, in for your TimeViewCell, you have to add your UIStackView IBOulet (or add it programmatically) and the configure method.
class TimeViewCell: UITableViewCell {
#IBOutlet var labelStackView: UIStackView!
func configure(data: Array<String>) {
for time in data {
let timeLabel = UILabel()
timeLabel.text = time
labelStackView.addArrangedSubview(label)
}
}
}
In my first tableViewController has navigationViewController.push(myNextController, animated: true) and I want to segue to another TableViewController. What I am trying to figure out for hours is that when I select a row in my first tableViewController, I want to move to the next tableview. Right now, when I select a row, my next tableVIew has the same data. I want each cell to have differently saved cells
Second table view controller
The title is the navigation title and the myArray is an array:
// globally declared
var dataArray = [String]()
var myArray = [String]()
// this function is in my second table view controller, viewDidLoad()
func data(){
myArray = UserDefaults.standard.stringArray(forKey: "Key")!
dataArray = myArray
}
The dataArray is:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as UITableViewCell
if let getData = UserDefaults.standard.stringArray(forKey:"key") {
cell.textLabel?.text = getData[indexPath.row]
}
tableView.reloadData()
return cell
}
first table view controller
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as UITableViewCell
cell.backgroundColor = UIColorUtil.rgb(rgbValue: 0xFFFFF9)
let getData = UserDefaults.standard.stringArray(forKey: "category")!
let nextViewController = TableView()
nextViewController._titile = getData[indexPath.row]
// so I access myArray from second table view controller because I want to
//get data of each selected cell. But this is a problem.
nextViewController.myArray = getData
self.navigationController?.pushViewController(nextViewController, animated:true)
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as UITableViewCell
if let getData = UserDefaults.standard.stringArray(forKey:"category") {
cell.textLabel?.text = getData[indexPath.row]
}
return cell
}
Why do they have the same cells? How am I able to accomplish this without using a storyboard? I want to programmatically write code. By the way, I am using UITabBar as well. Thanks!