By clicking on the red area I get a comment id. But I also want to get the id if I click on the blue button. How can I do that?
Right now I use this to detect a tap on a row. But tapping on button should run some other code.
extension FirstTabSecondViewComment: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
FirstTabSecondViewComment.subComment = table[indexPath.row].commentId ?? ""
print(FirstTabSecondViewComment.subComment)
self.performSegue(withIdentifier: "CommentDetail", sender: Any?.self)
}
}
After you have register your custom cell declare it in cellForRowAt and add target in button cell:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellId", for: indexPath) as! MyCell // your custom cell
// add target in buoon cell
cell.YourButtonCell.addTarget(self, action: #selector(submit(_:)), for: .touchUpInside)
return cell
}
after that add submit func:
#objc fileprivate func submit(_ sender: UIButton) {
var superview = sender.superview
while let view = superview, !(view is UITableViewCell) {
superview = view.superview
}
guard let cell = superview as? UITableViewCell else {
print("button is not contained in a table view cell")
return
}
guard let indexPath = tableView.indexPath(for: cell) else {
print("failed to get index path for cell containing button")
return
}
// We've got the index path for the cell that contains the button, now do something with it.
print("button is in index \(indexPath.row)")
}
This is a full code example, copy and paste in a new project and run:
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
let tableView = UITableView()
let cellId = "cellId"
override func viewDidLoad() {
super.viewDidLoad()
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
tableView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
tableView.delegate = self
tableView.dataSource = self
tableView.register(MyCell.self, forCellReuseIdentifier: cellId)
}
#objc fileprivate func submit(_ sender: UIButton) {
var superview = sender.superview
while let view = superview, !(view is UITableViewCell) {
superview = view.superview
}
guard let cell = superview as? UITableViewCell else {
print("button is not contained in a table view cell")
return
}
guard let indexPath = tableView.indexPath(for: cell) else {
print("failed to get index path for cell containing button")
return
}
// We've got the index path for the cell that contains the button, now do something with it.
print("button is in index \(indexPath.row)")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! MyCell
// add target in buoon cell
cell.cancelButton.addTarget(self, action: #selector(submit(_:)), for: .touchUpInside)
return cell
}
}
class MyCell: UITableViewCell {
let cancelButton: UIButton = {
let b = UIButton(type: .system)
b.backgroundColor = .white
b.setTitle("get Index", for: .normal)
b.layer.cornerRadius = 10
b.clipsToBounds = true
b.titleLabel?.font = .systemFont(ofSize: 16, weight: .semibold)
b.tintColor = .black
b.translatesAutoresizingMaskIntoConstraints = false
return b
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.backgroundColor = .darkGray
contentView.addSubview(cancelButton)
cancelButton.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
cancelButton.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true
cancelButton.heightAnchor.constraint(equalToConstant: 50).isActive = true
cancelButton.widthAnchor.constraint(equalToConstant: 300).isActive = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Related
let cell = tableView.dequeueReusableCell(withIdentifier: CellButton.identifier(), for: indexPath) as! CellButton
cell.build(height: 40, color: .lighterGray())
cell.blockAction = {
let category = categories?[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier:
CellCheck.identifier(), for: indexPath) as!
CellCheck
}
return cell
This is the code I have and when blockAction called (function called when i tap button in cell) I need to build another TableViewCell and remove first that appear
Is there any way of loading it inside same cell and also expand the height by the height of dynamic cell content
You could remove IndexPath and then add add a new indexPath.
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
private var buttonTapped: Bool = false
private var selectedIndexPath: IndexPath?
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
tableView.register(UINib(nibName: "TableViewCell", bundle: nil), forCellReuseIdentifier: "TableViewCell")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if buttonTapped == true,
let olderIndexPath = selectedIndexPath,
selectedIndexPath == olderIndexPath {
let cell = UITableViewCell()
cell.backgroundColor = .red
return cell
}
let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath) as! TableViewCell
cell.callback = {[weak self] in
self?.buttonTapped = true
self?.selectedIndexPath = indexPath
self?.insertNewCell(indexPath)
}
return cell
}
private func insertNewCell(_ indexPath: IndexPath) {
tableView.beginUpdates()
tableView.deleteRows(at: [indexPath], with: .right)
tableView.insertRows(at: [indexPath], with: .left)
tableView.endUpdates()
}
}
The code below creates a tableviewcell and places a object in it. The code to place data inside the tableviewcell is not present. All I want to do is when the user clicks on the tableviewcell it to be transfers to a basic view controller class. No need to show how to go back.
var itemName : [NSManagedObject] = []
var theField = UITableView()
override func viewDidLoad() {
super.viewDidLoad()
theField.register(UITableViewCell.self, forCellReuseIdentifier: "MyCell")
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let title = itemName[indexPath.row]
let cell = theField.dequeueReusableCell(withIdentifier: "MyCell", for : indexPath)
cell.selectionStyle = .default
let attr1 = title.value(forKey: "name") as? String
let text = [attr1].flatMap { $0 }.reduce("", +)
cell.textLabel?.text = "\(text)"
cell.textLabel?.textAlignment = .center
cell.layoutMargins = UIEdgeInsets.zero
cell.preservesSuperviewLayoutMargins = false
cell.separatorInset = UIEdgeInsets.zero
cell.layoutMargins = UIEdgeInsets.zero
return cell
}
#objc func moveRight() {
//pass tableview cell
let vce = fullScreen()
vce.text = UITableViewCell
vce.modalPresentationStyle = .overCurrentContext // actually .fullScreen would be better
vce.present(vce, animated: true)}
Assume you have an array titles
cell.textLabel?.text = titles[indexPath.row]
and then take action in this method:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
moveRight(titles[indexPath.row])
}
func moveRight(_ title:String) {
//pass tableview cell
let vc = fullScreen()
vc.text = title
self.navigationController!.pushViewController(vc, animated: true)
}
You need to implement the UITableViewDelegate protocol. So:
extension ViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { .. }
}
I just cannot seem to update data in Swift! I am trying to build a radio player app for a friends radio station so when a song changes I need to update the playlist viewcontroller.
The data from my Main View Controler is a instance of a struct. I know there is data being generated and it is passed to the table but for whatever reason the array isn't updating. I am sure it is something simple.
I have tried directly injecting the data with a call, using a protocol and using a function. Using the protocol and function I can see the passed data via print statement.
class PlaylistVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
//Mark: Variables ~~~~~~~~~~~~###########################################
var sourceDatas = [PlaylistData]()
//Mark: View Containers ~~~~~############################################
private let bg = GradientBG()
private let closeButton = UIButton()
let playlistTable = UITableView()
//Mark: Overrides ~~~~~~~~~~~~###########################################
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
playlistTable.delegate = self
playlistTable.dataSource = self
layoutUI()
setupTable()
setupClose()
}
//Mark: objc func's ~~~~~~~~~~~###########################################
#IBAction func handleXButton() {
dismiss(animated: true, completion: nil)
}
func handleMoreInfo(_ playlist: PlaylistData) {
let vc = SongPopUp()
vc.buildLables(playlist)
vc.modalPresentationStyle = .overCurrentContext
self.present(vc, animated: true, completion: nil )
}
//##################################################################
//Mark: Pass Data ##################################################
//Mark: Not Working!! ##############################################
//##################################################################
func handlePlaylist(_ with: PlaylistData) {
print(with)
sourceDatas.append(with)
//sourceDatas.insert(with, at: 0)
playlistTable.reloadData()
}
//Mark: Table view ################################################
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sourceDatas.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:UITableViewCell = UITableViewCell(style: .subtitle, reuseIdentifier: "myCell")
cell.backgroundColor = .clear
cell.selectionStyle = .none
tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath)
if let text = cell.textLabel {
components.layoutHeadingLable(sender: text, title: sourceDatas[indexPath.row].heading, size: 20)
}
if let dtext = cell.detailTextLabel {
components.layoutSubheadingLable(sender: dtext, title: sourceDatas[indexPath.row].subheading, size: 14)
}
if sourceDatas[indexPath.item].hasStoreLink {
cell.accessoryType = .detailButton
cell.tintColor = .white
}
return cell
}
func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
let dataToPass = self.sourceDatas[indexPath.row]
print("Extended~~~~~~~~~~~~~~~~~~~~")
print(dataToPass)
handleMoreInfo(sourceDatas[indexPath.row])
}
//Mark: Setup Table ~~~~~~~~~~~~~~###########################################
func setupTable() {
playlistTable.backgroundColor = .clear
playlistTable.separatorStyle = .singleLine
playlistTable.rowHeight = 45
playlistTable.register(UITableViewCell.self, forCellReuseIdentifier: "myCell")
}
......
I think it's something wrong with your cellForRowAt
Try to make it simple first, like:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath) as! UITableViewCell
cell.textLabel?.text = sourceDatas[indexPath.row]
return cell
}
See whether you can find the added object. Then dive into the detail settings of your cell.
Heyy,
Hello I want to implement a gesture in a tableview cell but it does not work here is my code:
var panGesture: UIPanGestureRecognizer?
override func awakeFromNib() {
super.awakeFromNib()
panGesture = UIPanGestureRecognizer(target: self, action: #selector(detectPan(recognizer:)))
panGesture?.delaysTouchesBegan = false
panGesture?.delaysTouchesEnded = false
separatorView.addGestureRecognizer(panGesture!)
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
#objc func detectPan(recognizer: UIPanGestureRecognizer) {
let translation = recognizer.translation(in: self.vc?.view)
switch recognizer.state {
case .began:
self.startingConstant = self.constantCenter.constant
case .changed:
self.constantCenter.constant = self.startingConstant + translation.x
case .ended:
if translation.x > 0 {
constantCenter.isActive = false
constanteGauche.isActive = false
constanteDroite.isActive = true
}else{
constantCenter.isActive = false
constanteGauche.isActive = true
constanteDroite.isActive = false
print("ok")
}
UIView.animate(withDuration: 0.2) {
self.vc?.view.layoutIfNeeded()
}
constantCenter.constant = separatorView.center.x - (self.vc?.view.center.x)!
constantCenter.isActive = true
constanteGauche.isActive = true
constanteDroite.isActive = true
default:
break
}
}
Do I have to fix something in my function tableview:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//On lien le TableViewCell
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? FeedCell
cell?.selectionStyle = .none
cell?.vc = self
cell?.delegate = self
cell?.view(post: FeedPostController.posts[indexPath.row], user: FeedPostController.users[indexPath.row]); //On passe l'objet a l'index i a la fonction view du TableViewCell pour l'affichage
return cell!;
}
I tried a lot of possibilities but nothing works, the function of the gesture I need it in the uitableviewcell because I use constraints that are in the cell
UPDATE SOLUTION
override func awakeFromNib() {
super.awakeFromNib()
separatorView.isUserInteractionEnabled = true //THIS LINE ITS VERY IMPORTANT !!!!!!!!
panGesture = UIPanGestureRecognizer(target: self, action: #selector(detectPan(recognizer:)))
panGesture?.delaysTouchesBegan = false
panGesture?.delaysTouchesEnded = false
separatorView.addGestureRecognizer(panGesture!)
}
Here is the code example. 100% works. Hope, it'll help.
import UIKit
private let cellID = "cellID"
class ViewController: UIViewController {
// Setup Table View
private lazy var tableView: UITableView = {
let rect: CGRect = view.bounds
let tableView = UITableView(frame: rect, style: .grouped)
tableView.separatorStyle = .singleLine
tableView.backgroundColor = .white
tableView.dataSource = self
tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellID)
// If you need to PAN the tableView, uncomment this line
// tableView.addGestureRecognizer(self.panGesture)
return tableView
}()
// Setup panGesture
private lazy var panGesture: UIPanGestureRecognizer = {
let pan = UIPanGestureRecognizer(target: self, action: #selector(didPan(sender:)))
// Set delegate
pan.delegate = self
return pan
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(tableView)
}
}
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath)
cell.backgroundColor = .red
// Add panGesture to first cell for example
if indexPath.section == 0, indexPath.row == 0 {
cell.addGestureRecognizer(self.panGesture)
cell.backgroundColor = .lightGray
cell.textLabel?.text = "You can drag a table for this cell"
}
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
}
extension ViewController: UIGestureRecognizerDelegate {
#objc fileprivate func didPan(sender: UIPanGestureRecognizer) {
let translation = sender.translation(in: view)
switch sender.state {
case .began:
print("Began")
case .changed:
print("Canged \(translation.y)")
// This is just example to show you how that works. Dragging tableView.
tableView.frame.origin.y = translation.y
case .ended:
print("Ended")
default:
break
}
}
}
Link for short video how it works on device: https://www.dropbox.com/s/1lorvamynbwvyv7/TJCQ1216.MP4?dl=0
If you have any questions, just ask )
I would like to perform a segue to a new VC by clicking on a UIButton that is found with in a cell (a Users Cell)
class TableViewController: UITableViewController {
var userScreenVC: usersScreenVC?
var HomePageVc: HomePageVC?
var signInVC: SignInVC?
var ref = FIRDatabase.database().reference()
let cellId = "cellId"
var users = [User]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UserCellLargePicture.self, forCellReuseIdentifier: cellId)
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return users.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! UserCellLargePicture
cell.selectionStyle = .none
cell.preservesSuperviewLayoutMargins = false
cell.separatorInset = UIEdgeInsets.zero
cell.layoutMargins = UIEdgeInsets.zero
let user = users[indexPath.row]
cell.ProfileButton.setImage(#imageLiteral(resourceName: "Grape"), for: .normal)
return cell
}//func tableview cellForRowAt
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 234
}
class UserCellLargePicture: UITableViewCell {
var ProfileButton: UIButton = {
let button = UIButton()
//label.text = "TEST TEST TEST"
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: .subtitle, reuseIdentifier: reuseIdentifier)
addSubview(ProfileButton)
ProfileButton.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -58).isActive = true
ProfileButton.widthAnchor.constraint(equalToConstant: 54).isActive = true
ProfileButton.heightAnchor.constraint(equalToConstant: 54).isActive = true
ProfileButton.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant:0).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}