I have the button working correctly, I just can't figure out how to disable it on tap. I'm not sure if I can reference it from the addSomething(sender: UIButton) function like I reference the sender.tag.
Any idea? Thanks for any help.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let myCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! ExploreCell
// Configure the cell...
myCell.configureCell(teams[indexPath.row])
myCell.addSomethingButton.tag = indexPath.row
myCell.addSomethingButton.addTarget(self, action: #selector(self.addSomething), forControlEvents: .TouchUpInside)
myCell.addSomethingButton.enabled = true
//disable cell clicking
myCell.selectionStyle = UITableViewCellSelectionStyle.None
return myCell
}
What do you need to do is to store all tapped buttons in an array to check whether the button of this tag (current indexPath.row) has been tapped:
class ViewController: UIViewController {
var tappedButtonsTags = [Int]()
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let myCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! ExploreCell
// Configure the cell...
myCell.configureCell(teams[indexPath.row])
myCell.addSomethingButton.tag = indexPath.row
// here is the check:
if tappedButtonsTags.contains(indexPath.row) {
myCell.addSomethingButton.enabled = false
} else {
myCell.addSomethingButton.addTarget(self, action: #selector(self.addSomething), forControlEvents: .TouchUpInside)
myCell.addSomethingButton.enabled = true
}
//disable cell clicking
myCell.selectionStyle = UITableViewCellSelectionStyle.None
return myCell
}
// I just Implemented this for demonstration purposes, you can merge this one with yours :)
func addSomething(button: UIButton) {
tappedButtonsTags.append(button.tag)
tableView.reloadData()
// ...
}
}
I Hope this helped.
Related
I have a tableView with 2 custom xib cells. I want to switch the custom cell when user tapped it also adjust the cell height. How do I achieve it? I tried to use container view but then the height would be the same. I want to know if it is possible to do it with two xib for tableView cell? Thank you.
var isContactView: Bool = true
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
tableView.register(UINib(nibName: "ContactTableViewCell", bundle: nil), forCellReuseIdentifier: "contactCell")
tableView.register(UINib(nibName: "DetailTableViewCell", bundle: nil), forCellReuseIdentifier: "detailCell")
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
//if ContactTableViewCell return 40
//if DetailTableViewCell return 150
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//by default the cell view is ContactTableViewCell.
//When user tapped the cell it will change to DetailTableViewCell.
if isContactView {
let cell = tableView.dequeueReusableCell(withIdentifier: "contactCell", for: indexPath) as! ContactTableViewCell
//do something...
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "detailCell", for: indexPath) as! DetailTableViewCell
//do something...
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//not sure how to change the xib in here.
//if cell view is ContactTableViewCell
cell view = tableView.dequeueReusableCell(withIdentifier: "detailCell", for: indexPath) as! DetailTableViewCell
isContactView = false
tableView.reloadData()
//else
cell view = tableView.dequeueReusableCell(withIdentifier: "contactCell", for: indexPath) as! ContactTableViewCell
isContactView = true
tableView.reloadData()
}
There are 2 cases:
If there's just single cell to be viewed, then just put the following code in didSelect:
isContactView = !isContactView
tableView.reloadData()
If there are multiple cells in which the condition is to be applied. Please put a key in your data model.
For example:
testArr is the array of objects that you are displaying in tableview. Then keep a key, say isContactView in this model. And put the login based upon this key.
Like in case of cellForRow:
if testArr[indexpath.row].isContactView {
let cell = tableView.dequeueReusableCell(withIdentifier: "contactCell", for: indexPath) as! ContactTableViewCell
//do something...
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "detailCell", for: indexPath) as! DetailTableViewCell
//do something...
}
And in didselect:
isContactView = !testArr[indexPath.row].isContactView
I want to delete tableview cell by clicking a button present in the same cell. But I am unable to access the cell in the button action function.
Please help me to Access this cell. My code is -
class MatchesViewController: UIViewController{
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "MatchingUsersTVCell") as? MatchingUsersTVCell else{
return UITableViewCell()
}
let likeUid = userIdArray[indexPath.row]
cell.heartBtn.tag = indexPath.row
cell.heartBtn.addTarget(self, action: #selector(userLikeButtonWasTappaed(sender:)), for: .touchUpInside)
}
#objc func userLikeButtonWasTappaed(sender: UIButton){
if let cell = sender.superview as? MatchingUsersTVCell{
CellAnimator.animate(cell: cell)
}
let tag = sender.tag
let userid = userIdArray[tag]
}
}
Try this code:
#objc func userLikeButtonWasTappaed(sender: UIButton){
guard let indexPath = tableView.indexPathForRow(at: sender.convert(sender.frame.origin, to: tableView)) else {
return
}
let cell = tableView.cellForRow(at: indexPath) as? MatchingUsersTVCell
}
And in your cellForRowAt function add the following code:
cell.yourBtn.tag = indexPath.row
cell.yourBtn.addTarget(self, action: #selector(userLikeButtonWasTappaed(sender:)), for: .touchUpInside)
I'd stay away from using tags, and instead implement protocol/delegate.
Using indexPath allows use of multiple sections, etc...
1) Create a protocol:
protocol MatchingUsersTVCellDelegate : class {
func didTapLikeButton(_ indexPath: IndexPath)
func didTapOtherButton(_ indexPath: IndexPath)
}
2) Create/Update your cell:
class MatchingUsersTVCell : UITableViewCell {
weak var delegate: MatchingUsersTVCellDelegate?
var indexPath: IndexPath!
// add target to your like button
func didTapLIkeButton(_ sender: UIButton) {
self.delegate?.didTapLikeButton(indexPath)
}
func didTapOtherButton() {
self.delegate?.didTapOtherButton(indexPath)
}
}
3) make sure your viewController conforms to the new delegate:
extension YourViewController: MatchingUsersTVCellDelegate {
func didTapLikeButton(_ indexPath: IndexPath) {
//Do something with the indexPath or indexPath.row
dataSource.remove(at: indexPath.row)
}
func didTapOtherButton(_ indexPath: IndexPath) {
//Do something else with the indexPath or indexPath.row
}
}
4) Set delegate and indexPath
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell...
cell.delegate = self
cell.indexPath = indexPath
return cell
}
Within MatchingUsersTVCell, add two properties, one named parentVC of type UIViewController and one named index of type Int:
class MatchingUsersTVCell: UITableViewCell {
var parentVC: UIViewController!
var index: Int!
...
}
Then, when creating each cell, set these two values appropriately:
class MatchesViewController: UIViewController, UITableViewDelegate, UITableViewDatasource {
...
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "MatchingUsersTVCell") as? MatchingUsersTVCell else {
return UITableViewCell()
}
cell.parentVC = self
cell.index = index
...
return cell
}
}
Now, you simply update your parentVC's tableView's data source and reload its data whenever the button is tapped:
class MatchingUsersTVCell: UITableViewCell {
...
#objc func userLikeButtonWasTappaed(sender: UIButton){
parentVC.userIdArray.remove(at: index)
parentVC.tableView.reloadData()
}
}
you can get it like this in your selector method
#objc func userLikeButtonWasTappaed(button:UIButton){
guard let indexPath = myTableView.indexPathForRow(at: button.convertPoint(button.frame.origin, toView: myTableView)) else {
print("Error: indexPath)")
return
}
print("indexPath.row: \(indexPath.row)")
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
...
let doLikeBtn = detailCell.contentView.viewWithTag(106) as! UIButton
doLikeBtn.setTitle(String(indexPath.row), for: UIControlState.normal)
doLikeBtn.addTarget(self, action: #selector(doLike(sender:)), for: UIControlEvents.touchUpInside)
...
}
...
func doLike(sender: UIButton) {
selectUserIndex = sender.title(for: UIControlState.normal)!
if sender.image(for: UIControlState.normal) == UIImage(named: "btn_Like.png") {
sender.setImage(UIImage(named: "btn_not_Like.png"), for: UIControlState.normal)
}else {
sender.setImage(UIImage(named: "btn_Like.png"), for: UIControlState.normal)
}
}
If I click one button in table, and then change the image of button, but other some button's images also are changed repeatedly.
I can't understand this.
Please help me!
Best regards.
a UITableViewCell object is reusable—that is for performance reasons,
you should only reset attributes of the cell that are not related to
content.
So you need to update your cell every time cellForRowAt invoked:
also you need to keep track of which cell getting "liked or dislike" so you can add for example a boolean isLike property to YourCustomCell
and toggle it true or false upon doLike func triggered
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.deque... as! YourCustomCell
if cell.isLiked == false {
cell.btnSomething.setImage(UIImage(named: "btn_not_Like.png"), for: UIControlState.normal)
}else {
cell.btnSomething.setImage(UIImage(named: "btn_Like.png"), for: UIControlState.normal)
}
}
Updated for Swift 3/4:
Use lines of code to change/set the UIButton Image in UITableView;
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "YourTableViewCellStoryboardIdentifier")! as! YourTableViewCellName
if status == 1{
cell.mStatusButtonOutlet.setImage(UIImage(named: "pending_icon"), for: .normal)
}else if status == 2{
cell.mStatusButtonOutlet.setImage(UIImage(named: "approval"), for: .normal)
}else if status == 3{
cell.mStatusButtonOutlet.setImage(UIImage(named: "reject_icon"), for: .normal)
}else{
cell.mStatusButtonOutlet.setImage(UIImage(named: "cancle"), for: .normal)
}
return cell
}
Note: where mStatusButtonOutlet - is your UIButtonOutlet
Enjoy..!
In Swift 4, Below is a simple way to do it
class AddressTableViewCell: UITableViewCell {
#IBOutlet weak var starButton: UIButton!
var buttonObject : (() -> Void)? = nil
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
#IBAction func buttonPressed(sender: UIButton) {
if let buttonAction = self.buttonObject {
buttonAction()
}
}
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "addressTableViewCell", for: indexPath) as! AddressTableViewCell
cell.buttonObject = {
if cell.starButton.currentImage == UIImage(named: "fav") {
cell.starButton.setImage(UIImage(named: "favYellow"), for: .normal)
} else {
cell.starButton.setImage(UIImage(named: "fav"), for: .normal)
}
}
return cell
}
In my UITableView I'm attempting to have a button that will have a different action for each cell i.e. links to different viewController, for each button but i've only managed to achieve it with one.
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return courseTitle.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! CustomCell
cell.image_view.image = courseImages[indexPath.row]
cell.title.text = courseTitle[indexPath.row]
cell.tableButton.tag = indexPath.row
cell.tableButton.addTarget(self, action: "Test", forControlEvents: UIControlEvents.TouchUpInside)
return cell
}
#IBAction func Test(sender: AnyObject){
self.performSegueWithIdentifier("SuccessfulLogin", sender: nil)
}
If you have just few cells you can do it like so:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! CustomCell
cell.image_view.image = courseImages[indexPath.row]
cell.title.text = courseTitle[indexPath.row]
cell.tableButton.tag = indexPath.row
switch indexPath.row {
case 0:
cell.tableButton.addTarget(self, action: "TestA", forControlEvents: UIControlEvents.TouchUpInside)
case 1:
cell.tableButton.addTarget(self, action: "TestB", forControlEvents: UIControlEvents.TouchUpInside)
case 2:
cell.tableButton.addTarget(self, action: "TestC", forControlEvents: UIControlEvents.TouchUpInside)
default:
cell.tableButton.addTarget(self, action: "TestD", forControlEvents: UIControlEvents.TouchUpInside)
}
return cell
}
func TestA(sender: AnyObject){ // no need for #IBAction as you set the target action while setting the cell
self.performSegueWithIdentifier("SuccessfulLogin", sender: nil)
}
func TestB(sender: AnyObject){
print("Second button action")
}
func TestC(sender: AnyObject){
print("Third button action")
}
func TestD(sender: AnyObject){
print("All other buttons action")
}
You can use that tag value for that and change your selector syntax also
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! CustomCell
cell.image_view.image = courseImages[indexPath.row]
cell.title.text = courseTitle[indexPath.row]
cell.tableButton.tag = indexPath.row
cell.tableButton.addTarget(self, action: "test:", forControlEvents: UIControlEvents.TouchUpInside)
return cell
}
#IBAction func test(sender: UIButton){
let row = sender.tag
switch(row) {
case 0:
self.performSegueWithIdentifier("Segue1", sender: nil)
case 1:
self.performSegueWithIdentifier("Segue2", sender: nil)
case 2:
self.performSegueWithIdentifier("Segue3", sender: nil)
default:
}
}
I have a tableview that contains a button in the left of cell. the run works well and when i select a button a made it change its image background. The problem is when I select a buttonButtonOne selection , it select other buttons when I scroll tableview down, Other buttons selected my code is this way:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableview.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! PlayerCell
cell.BtnAdd.tag = indexPath.row
cell.BtnAdd.addTarget(self, action: #selector(CreateTeamTwo.PlayerAdded(_:)), forControlEvents: .TouchUpInside)
return cell
}
func PlayerAdded(sender: UIButton){
// let buttonTag = sender.tag
sender.setImage(UIImage(named: "btn_buy_minus.png"), forState: UIControlState.Normal)
}
can you help me please ?
Take one Array to store selected indexPaths Buttons tags. and in selector methods store all the sender tags and reload the tableView. and in cellForRow method check if current indexpath is contain in selected array then show minus image otherwise show plus image.
var selected = [Int]()
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableview.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! PlayerCell
cell.BtnAdd.tag = indexPath.row
cell.BtnAdd.addTarget(self, action: #selector(CreateTeamTwo.PlayerAdded(_:)), forControlEvents: .TouchUpInside)
if selected.contains(indexPath.row) {
cell.btn.setImage(UIImage(named: "btn_buy_minus.png"), forState: .Normal)
} else {
// here set the plus image
cell.btn.setImage(UIImage(named: "btn_buy_plus.png"), forState: .Normal)
}
return cell
}
func PlayerAdded(sender: UIButton){
selected.append(sender.tag)
self.tableView.reloadData()
}