When a button is clicked (thats located inside the cell of a tableview), I pass a reference to it to another class. However, along with it I also want to pass a reference to another button in the same cell. I can easily reference the clicked button as "sender", but how would I reference the other button in the same cell?
This is in the cell subclass, not the main view controller.
class ImageTableViewCell: UITableViewCell {
#IBOutlet weak var upVote: UIButton!
#IBOutlet weak var downVote: UIButton!
#IBAction func upVote(sender: AnyObject) {
self.delegate?.controller(self, button: sender as! UIButton, other: *REFERENCE DOWNVOTE BUTTON HERE*, selectedButtonIndexPath: indexPath!)
}
}
The cell has a property for each button.
Since it appears that you have separate action methods for each button, the other button is known to you and you can pass it directly:
#IBAction func upVote(sender: AnyObject) {
self.delegate?.controller(self, button: sender as! UIButton, other: downVote, selectedButtonIndexPath: indexPath!)
}
If you don't know which button is which, you can determine the opposite button by
let other = sender === self.upVote ? self.downVote : self.upVote
Related
I have a tableView with a custom cell that has a UITextView inside it and I want to make the UITextView of the last cell in the tableView the firstresponder when a button is pressed. However, I'm not sure how to reference that UITextView inside the cell.
It has an outlet in the custom cell class, but I don't know how to use this button (an action in another class) to reference it.
class ActionCell: UITableViewCell {
#IBOutlet weak var label: UITextView!
}
What I tried is this, but it doesn't work:
#IBAction func addAction(_ sender: Any) {
let cell = tableview.cellForRow(at: IndexPath.init(row: -1, section: 1)) as? ActionCell
let textview = cell?.contentView.subviews.filter{$0 is UITextView}
textview![0].becomeFirstResponder()
}
I have an app which utilizes a tableView which contains a prototype cell. This prototype cell contains a few labels and a button (connected to that cell's UITableViewCell file). If that's not clear, this is what I mean:
class ContactsCell: UITableViewCell { //this custom cell is used as the prototype cell for the tableView
#IBOutlet weak var firstNameLabel: UILabel!
#IBOutlet weak var lastNameLabel: UILabel!
#IBOutlet weak var numberLabel: UILabel!
#IBOutlet weak var indexPathRowLabel: UILabel!
#IBOutlet weak var replaceContactButtonUI: UIButton!
#IBAction func replaceContactButtonTapped(_ sender: Any) {
//THIS is the button in question
}
The reason for this is because I'd like each cell in the tableView to have all of those labels (and the button), but with each row having different values in the labels. These values are handled by the cellForRowAt tableView function, via a system as follows:
Pressing a button (not the button in the cells I was talking about... a different button that is at the top of the VC, outside of the tableView) brings up the contact picker:
func selectContact(){//allows user to bring up contactPicker
let contactPicker = CNContactPickerViewController()
contactPicker.displayedPropertyKeys = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactPhoneNumbersKey, CNContactImageDataKey]
contactPicker.delegate = self
contactPicker.predicateForEnablingContact = NSPredicate(format: "phoneNumbers.#count >= 0")
contactPicker.predicateForSelectionOfContact = NSPredicate(format: "phoneNumbers.#count >= 1")
self.present(contactPicker, animated: true, completion: nil)
}
#IBAction func selectContactsButton(_ sender: Any) {
selectContact()
//button brings up the picker to allow selection of contact
}
Selecting one of the contacts updates an array which is used by the tableView to update the value of the labels:
func contactPicker(_ picker: CNContactPickerViewController, didSelect contactProperty: CNContactProperty) {
contactArray.append(contactProperty.contact)
print(contactArray)// contactArray = [CNContact]()
contactsTableView.reloadData()// reloads the value of the labels
dismiss(animated: true)
}
These all work as intended. However, I run into a bit of an issue with the button that is in each cell. This button is intended to allow the replacement of a the CNContact in the tableView at the row of which the button was pressed... (ie if there are 4 rows, there are 4 "replace" buttons. Clicking the "replace" button of the third row replaces the CNContact at the 2nd index of the contactArray). This is where my issue is, though. Since the button, and its action, lives in the UITableViewCell's swift file, and not in the tableViewControllers, it doesn't have access to the contactArray to remove and append, nor the picker functions to allow the selection of the new contact, nor the tableView itself to run .reloadData(). How do I 'give access' to the UITableViewCell's swift file to utilize things from the tableView controller that it is a part of/connected to?
Note Its possible that the entire premise of this question is wrong and that I should've actually placed the button's action elsewhere (not in the UITableViewCell's swift file). If this is the case, where should I put it?
Since you have all the information in your ViewController, I would suggest moving your #IBAction into your ViewController as well. If you are worried about referencing the correct cell, you can set the tag value of your UIButton in cellForRow method. Then in #IBAction, you can use that value to access the correct index in the array as well as the cell itself
you can give selector to button in cellforrowatindexpath:
cell.replaceContactButtonUI.tag = index.row
cell.replaceContactButtonUI.addTarget(self, action: #selector(self.
selectContact(sender:)), for: .touchUpInside)
func selectContact(sender:UIButton){}
From button tag you can find the cell index by sender.tag.
How to delete a row from tableview using custom buttom
//CustomCell.swift
protocol FavoriteCellDelegate {
func deleteButton(sender:CustomCell)
}
class FavoriteItemTableViewCell: UITableViewCell{
var delegate: FavoriteCellDelegate!
#IBAction func deleteButton(_ sender: UIButton) {
delegate.deleteButton(sender: self)
}
}
CustomClass:UITableViewDataSource,UITableViewDelegate,CustomCellDelegate{
#IBOutlet weak var tableView: UITableView!
// all necessary functions for table view....
// Function delegated to perform action.
func deleteButton(sender:FavoriteItemTableViewCell){
//How should I delete. How can I get index path here
}
}
Q. What should I write in the deleteButton function ? I am unable to get the indexPath here so what should I do instead. I already have another button in cell and the delegation is working fine.
you can get indexPath using table view point like this
let buttonPosition : CGPoint = sender.convert(sender.bounds.origin, to: tableview)
let indexPath = tableview.indexPathForRow(at: buttonPosition)
I have a UICollectionViewCell header on a UICollectionViewController, and I've added a button to it. I would like for the button, when clicked, to push a new view controller atop the current one. The problem is that the button doesn't have access to the navigation controller of the UICollectionViewController, so I there's no way to directly push a controller from, say, a connector to the buttn (that I know of). Is there any way to achieve this? Maybe something can be overriden, such as a collectionView function. Thanks!
If you just want to process the cell selection there is a handy method in the UICollectionViewDelegate that you can implement to get the index path of the pressed cell.
If your goal is to have a custom button inside the cell (or maybe even several) you can use delegation pattern to retrieve user actions to your controller to than process in any way, including pushing/presenting new controllers. Assign the controller's instance (the one managing the collection view) to the delegate member of your cell.
Define a protocol that I would call something like MyCustomCellDelegate (replace MyCustomCell with a more appropriate name for your case). Something like MyCustomCellDelegate: class { func didPressButtonX() }
Declare an optional delegate property in your cell subclass. weak var delegate: MyCustomCellDelegate?
Implement your delegate protocol by the class you want to respond to button presses (or any other interactions defined by your protocol).
Every time you create/dequeue a cell for your UICollectionView to use you set the delegate property to the view controller managing the collection view. cell.delegate = self (if done inside the view controller itself).
After receiving the UI event inside your custom cell use your delegate property to retrieve the action to the controller (or with ever object you used when assigning the property). Something like: delegate?.didPressButtonX()
In your class that implements MyCustomCellDelegate use the method to push the new controller.
Below I will provide sample code that should give more details on the implementation of the proposed solution:
// In your UICollectionViewCell subclass file
protocol MyCustomCellDelegate: class {
func didPressButtonX()
func didPressButtonY()
}
MyCustomCell: UICollectionViewCell {
weak var delegate: MyCustomCellDelegate?
#IBOutlet var buttonX: UIButton!
#IBOutlet var buttonY: UIButton!
#IBAction func didPressButtonX(sender: Any) {
delegate?.didPressButtonX()
}
#IBAction func didPressButtonY(sender: Any) {
delegate?.didPressButtonY()
}
}
// Now in your UICollectionViewController subclass file
MyCustomCollectionViewController: UICollectionViewController {
// ...
override func collectionView(UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier identifier: "YourCellIdentifierGoesHere", for indexPath: indexPath) as! MyCustomCell
// In here we assign the delegate member of the cell to make sure once
// an UI event occurs the cell will call methods implemented by our controller
cell.delegate = self
// further cell setup if needed ...
return cell
}
}
// In order for the instance of our controller to be used as cell's delegate
// we implement the protocol that we defined earlier in the cell file
extension MyCustomCollectionViewController: MyCustomCellDelegate {
func didPressButtonX() {
print("X button was pressed")
// now lets finally push some new controller
let yourNextCoolViewController = UIViewController()
self.push(yourNextCoolViewController, animated: true)
// OR if you are using segues
self.performSegue(withIdentifier: "YourSegueIdentifierGoesHere", sender: self)
}
func didPressButtonY() {
print("Y button was pressed")
}
}
I have a custom UIView with 3 tableviews, the tableviews are self-sizing depending on the content they have, and they a show a different nib when they are empty than when they have content. All of this is embedded in a scroll view and it's working already, my view scrolls and the tableviews display the content appropriately and they autosize properly, the scroll view's size is adjusting without problems either.
In two of the tableviews when the tableviews have items there are some buttons in the cell nib that I want to access along with the index of the cell clicked inside the View controller where I have defined the Table view.
Here in the pic I'm showing the tableViews each with one item, the Canastas tableView has just a delete item button and the Productos tableView has a delete item button and a stepper to increase or decrease the amount.
I found a solution involving delegates in StackOverflow
Get button click inside UI table view cell, which I implemented. But for some reason it isn't working and the code in the delegate method isn't being executed.
Here is my code:
CanastasViewCell
import UIKit
protocol CanastasViewCellDelegate: class {
func closeButtonTapped(at index: IndexPath)
}
class CanastasViewCell: UITableViewCell {
#IBOutlet weak var imagenProducto: UIImageView!
#IBOutlet weak var nombreProducto: UILabel!
#IBOutlet weak var descProducto: UILabel!
#IBOutlet weak var precioProducto: UILabel!
#IBOutlet weak var closeButton: UIButton!
weak var delegate: CanastasViewCellDelegate?
var indexPath: IndexPath!
override func awakeFromNib() {
super.awakeFromNib()
}
#IBAction func eliminarProducto(_ sender: AnyObject) {
self.delegate?.closeButtonTapped(at: indexPath)
}
}
CarritoViewController
import UIKit
class CarritoViewController: UIViewController, UITableViewDelegate,
UITableViewDataSource, CanastasViewCellDelegate {
func closeButtonTapped(at index: IndexPath) {
print("Button tapped at index:\(index)")
}
It looks like you're not setting the delegate inside CarritoViewController. You'll want to make sure that you set cell.delegate = self inside func tableView(UITableView, cellForRowAt: IndexPath).