I have a button in my table and when it was click it will trigger the selected table index. for example when i click the button at a selected index it will trigger the code below. Thank You
code
func indexWasPressed(cell: ToDoListTableViewCell) {
trigger it here
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("You selected cell #\(indexPath.item)!")
Use below code to get index from TableViewCell:
func indexWasPressed(cell: ToDoListTableViewCell) {
let indexPath = yourTableView.indexPath(for: cell)
let index = indexPath.row
}
try this:-
#objc func buttonPressed(sender: UIButton) {
// printing selected row
print("index path: \(sender.tag)")
//do you want section try this
var section = Int()
let pointInTable: CGPoint = sender.convert(sender.bounds.origin, to: self.tblView)
let cellIndexPath = self.tblView.indexPathForRow(at: pointInTable)
section(cellIndexPath!)
section = cellIndexPath!.row
print(section)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
print("cell for rows in \(indexPath.section)")
let cell = tableView.dequeueReusableCell(withIdentifier: "cellIdentifire", for: indexPath) as! yourcell
cell.yourbutton.tag = indexpath.row
cell.yourbutton.addTarget(self, action: #selector(buttonpressed(sender:)), for: UIControlEvents.touchUpInside)
}
Related
I got a play button on my tableview custom cell, whenever I tapped the play button. I want the selected button image to change to pause image.
The issue is that all the other buttons images are getting updated.
So all the images are changing to the pause image, instead of the selected button.
I tried to get the indexpath of the button tapped and reload only that row, but that doesn't seem to make a difference.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let playerCell = tableView.dequeueReusableCell(withIdentifier: "playerCell", for: indexPath) as! PlayerCell
let item = subcategory?.items?[indexPath.row]
// Tap gestures extension for cell button action
playerCell.playPause.addTapGestureRecognizer {
AudioController.shared.setupPlayer(item: item)
if let selectedCell = tableView.cellForRow(at: indexPath) as? PlayerCell {
selectedCell.playPause.setImage(#imageLiteral(resourceName: "pause"), for: .normal)
tableView.reloadRows(at: [IndexPath(row: indexPath.row, section: 1)], with: .none)
}
print("index \(indexPath)")
}
What you can do is add a tag to the button. So within the method that you create the cells override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell, you add a tag to the button within that cells that represents the indexPath. Then from within the selector that you assign the button, you can get the cell that you want to alter.
For example:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "yourCell", for: indexPath)
cell.button.tag = indePath.row
cell.button.addTarget(self, action: #selector(yourSelector(_sender:)), for: .touchUpInside)
}
func yourSelector(_sender: UIButton){
let cell = tableView.cellForRow(at: IndexPath(row: sender.tag, section: 0)) as! YourCellType
// Change the image, play/pause audio for that cell
}
When you tap on the button in cell, tableView(_:didSelectRowAt:) won't be trigger, so I suggest using delegate to detect button action.
And you need to keep tracking the change of the cell's button status.
For example:
PlayCell.swift
protocol PlayCellDelegate: class {
func playCellPlayButtonDidPress(at indexPath: IndexPath)
}
class PlayerCell: UITableViewCell {
let playButton: UIButton = {
let button = UIButton()
button.addTarget(self, action: #selector(playButtonPressed(_:)), for: .touchUpInside)
return button
}()
weak var delegate: PlayCellDelegate?
var item: MyItem? {
didSet {
if item?.status == .paused {
// set pause image for playButton here
} else if item?.status == .playing {
// set play image for playButton here
}
}
}
var indexPath: IndexPath?
#objc func playButtonPressed(_ sender: UIButton) {
guard let indexPath = self.indexPath else { return }
delegate?.playCellPlayButtonDidPress(at: indexPath)
}
}
Model.swift
struct Subcategory {
// ...
var items: [MyItem]?
}
struct MyItem {
// ...
var status: Status.stop
enum Status {
case playing, paused, stopped // etc..
}
}
TableViewController.swift
class TableViewController: UITableViewController, PlayCellDelegate {
private var subcategory: Subcategory?
private let cellId = "Cell"
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as? PlayerCell {
cell.delegate = self
cell.item = subcategory?.items?[indexPath.row]
cell.indexPath = indexPath
return cell
}
return UITableViewCell()
}
func playCellPlayButtonDidPress(at indexPath: IndexPath) {
// you only need to change model here, and reloadRows will update the cell.
if subcategory?.items?[indexPath.row].status == .play {
subcategory?.items?[indexPath.row].status = .pause
} // other logic..
tableView.reloadRows(at: [indexPath], with: .none)
}
}
Hope it helps!
I have a TableView inside Another TableView, and the inner tableView contains buttons. I am able fire a method when click on button, but not able to get the indexPath. The app is getting crashed when I use the below code
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell") as! MyCell
cell.myButton?.addTarget(self, action:#selector(myButtonPressed(_:)), for:.touchUpInside)
return cell
}
#objc func myButtonButtonPressed(_ sender: AnyObject) {
let button = sender as? UIButton
let cell = button?.superview?.superview as? UITableViewCell
let clasObj = myCell()
let indexPath = myCell.InsidetabView.indexPath(for: cell!)
let index = (indexPath?.row)!
print(index)
}
I gave tag to the button on TableView, cellForRowAt indexPath Method and accessed it on buttonPressed method
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell") as! MyCell
cell.myButton?.addTarget(self, action:#selector(myButtonPressed(_:)), for:.touchUpInside)
cell.button.tag = indexPath.row
return cell
}
#objc func myButtonButtonPressed(_ sender: AnyObject) {
let button = sender as? UIButton
let row = button!.tag
}
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 a strange behavior in the UITABLEVIEW.
I have a TableView with Button, what I wanted to do is when I clicked to a button in the tableView, I want the color border to change to red.
The problem is that the color is changing not only for the clicked button, but also for others row in the tableview:
Here is my implementation
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! chooseProductTVC
cell.Btn_AddProduct.addTarget(self, action: #selector(self.btnAction(_:)), for: .touchUpInside)
return cell
}
#objc func btnAction(_ sender: MyButton) {
sender.BorderColor = UIColor.red
let point = sender.convert(CGPoint.zero, to: tbl_View_ChooseProduct as UIView)
let indexPath: IndexPath! = self.tbl_View_ChooseProduct.indexPathForRow(at: point)
let object = self.fetchedResultsController.object(at: indexPath)
print (object.produit_name)
print("row is = \(indexPath.row) && section is = \(indexPath.section)")
}
As you can see in the picture below I have only clicked on the first button (Abricot) ==> other button has also automatically changed the border (Avocat) and many others.
This is because of cell dequeuing try to re set when you load the table , suppose here default is blue
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
cell.Btn_AddProduct.addTarget(self, action: #selector(self.btnAction(_:)), for: .touchUpInside)
if selected
cell.Btn_AddProduct.BorderColor = UIColor.red
else
cell.Btn_AddProduct.BorderColor = UIColor.blue
return cell
}
Since we reuse the cell for displaying, we have to modify the color every time after dequeing.
Add new property selected to product model.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! chooseProductTVC
cell.Btn_AddProduct.addTarget(self, action: #selector(self.btnAction(_:)), for: .touchUpInside)
let object = self.resultArray(at: indexPath.row)
if object.selected
cell.Btn_AddProduct.BorderColor = .red
else
cell.Btn_AddProduct.BorderColor = .blue
return cell
}
#objc func btnAction(_ sender: MyButton) {
sender.BorderColor = UIColor.red
let point = sender.convert(CGPoint.zero, to: tbl_View_ChooseProduct as UIView)
let indexPath: IndexPath! = self.tbl_View_ChooseProduct.indexPathForRow(at: point)
let object = self.fetchedResultsController.object(at: indexPath)
object.selected = true
print (object.produit_name)
print("row is = \(indexPath.row) && section is = \(indexPath.section)")
}
Tip: You could use tableChooseProduct(iOS) instead of tbl_View_ChooseProduct.(android). This link may helpful.
You have to store default Colors in Dictionary.
var orderColor = [Int : UIColor]()
override func viewDidLoad() {
super.viewDidLoad()
for i in 0...29 // TotaL number of rows
{
orderColor[i] = UIColor.blue // DEFAULT color of the Button
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 30
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! chooseProductTVC
cell.Btn_AddProduct.addTarget(self, action: #selector(self.btnAction(_:)), for: .touchUpInside)
cell.Btn_AddProduct.BorderColor = orderColor[indexPath.row]
cell.selectionStyle = .none
return cell
}
#objc func btnAction(_ sender: MyButton) {
let point = sender.convert(CGPoint.zero, to: tbl_View_ChooseProduct as UIView)
let indexPath: IndexPath! = self.tbl_View_ChooseProduct.indexPathForRow(at: point)
orderColor[indexPath.row] = UIColor.red
tbl_View_ChooseProduct.reloadData()
}
I have a label inside a table view cell.
On click of the label I want to segue to another view controller after retrieving the correct indexPath.
I have added a gestureRecognizer to the label. On click of the label it returns the wrong indexPath , it does not return the index Path of the cell in which the label is.
How can I solve this problem . Any help will be appreciated. Thank you
Following is my code
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
cell = tableView.dequeueReusableCell(withIdentifier: "ViewControllerCell", for: indexPath) as! TableCell
cell.name.text = feeds[indexPath.row].name
nameClicked()
return cell
}
func nameClicked(){
cell.name.isUserInteractionEnabled = true
let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(TrendViewController.handleTap(gestureRecognizer:)))
cell.name.addGestureRecognizer(gestureRecognizer)
}
func handleTap(gestureRecognizer: UIGestureRecognizer) {
var touchPoint = cell.name.convert(CGPoint.zero, to: self.tableView)
var clickedLabelIndexPath = tableView.indexPathForRow(at: touchPoint)!
nameFromView = feeds[clickedLabelIndexPath.row].name
print("IndexPath at touch",clickedLabelIndexPath)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "profile") as! ProfileViewController
vc.clickedLabelIndexPath = clickedLabelIndexPath
vc.nameFromView = feeds[clickedLabelIndexPath.row].name
self.navigationController?.pushViewController(vc, animated: true)
}
You have declare cell as instance property in your class,so you are adding gesture to the same cell's label. So create new cell using dequeueReusableCell and changed your method nameClicked by adding argument of type cell.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//create new cell
let cell = tableView.dequeueReusableCell(withIdentifier: "ViewControllerCell", for: indexPath) as! TableCell
cell.name.text = feeds[indexPath.row].name
nameClicked(cell)
return cell
}
func nameClicked(_ cell: TableCell){
cell.name.isUserInteractionEnabled = true
let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(TrendViewController.handleTap(gestureRecognizer:)))
cell.name.addGestureRecognizer(gestureRecognizer)
}
Now change your handleTap method like this to get the correct indexPath.
func handleTap(_ gestureRecognizer: UIGestureRecognizer) {
let point = self.tableView.convert(CGPoint.zero, from: gestureRecognizer.view!)
if let indexPath = self. tableView.indexPathForRow(at: point) {
print("\(indexPath.section) \(indexPath.row)")
//Add your code here
}
}
Note: If your cell having only single cell then it is batter if you use didSelectRowAt method instead of adding gesture to label.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print(indexPath.row)
}
Maybe you should make condition for check if cell is touched ?
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ViewControllerCell", for: indexPath) as! TableCell
if cell.isTouched {
cell.setTouched
}
else {
cell.setNoTouched
}
return cell
}