Handle button click inside UITableViewCell - ios

I can't seem to handle a button click properly inside a custom UITableViewCell. It's a cell that contains a label and a button. I have the following code:
var cell = tableView.DequeueReusableCell (cellKey) as ApptHistoryCell;
if (cell == null)
{
cell = _container.Cell;
cell.SelectionStyle = UITableViewCellSelectionStyle.None;
}
if (InfoClicked != null)
{
cell.ActionButton.TouchUpInside += InfoClicked;
}
InfoClicked is an event handler passed on in loop on cell creation. When the cell is re-used, this causes a null reference exception, because (I think) TouchUpInside is trying to call 2 handlers. Old one and the new one, which causes a crash. If I put the event handler inside cell == null if block, then the wrong action is shown.
How can I handle the click properly?
Thanks!

The way I handle buttons inside custom cells:
I define an IBAction that I connect to a UIButton event inside the custom cell
I define a delegate and a delegate method for the cell to handle the button action
The IBAction calls that delegate method
When defining your cells in cellAtRow... I set the tableViewController to be the delegate. cell.delegate=self;
I do whatever action I would like to do inside that delegate method in the tableViewController
Makes sense?

you should create your cell from a xib file, which already connects the buttons to the owner's targets (the view controller).

In your custom cell just locate your button at IB and make connection with the property.
Now, in the controller at cellForRowAtIndexPath, what you need, just tag that button, say:
(MyCustomCell*)cell.myButton = indexPath.row;
Now, after that just set the click event like that:-
[(MyCustomCell*)cell.myButton addTarget:self action:#selector(NeedFunctionToCall:) forControlEvents:UIControlEventTouchUpInside];
Now, at same view controller, implement that required method, like that:
-(void)NeedFunctionToCall:(id)sender
{
NSLog("Got the event :-> %d, from the cell/button",[sender tag]);
}

Related

Create action for a button inside collection view

I have created a UICollection View inside a storyboard, I have created a button inside the cell, whenever I tap on the button I should filter the data as per my condition, so each and every buttons inside the cell will have different conditions, can anyone help me out with this issue ?? Iam using xcode 9 and swift 4.
Use addTarget of your button inside cellForItemAt:indexPath datasource and add a selector where action of the button will be defined. Add this button's tag, (add it same as your indexPath.row, that you can use to differentiate your button from collectionview)
cell.yourButton.addTarget(self, action: #selector(yourButtonTapped), for: .touchUpInside)
cell.yourButton.tag = indexPath.row
Now add the action of that button and inside that perform any action you need.
#IBAction func yourButtonTapped(_ sender: UIButton) {
//perform action
}
Create a custom UICollectionViewCell type. Wire up an IBAction to the cell.
Create a protocol that lets the cell notify the collection view that the user tapped a button. Have the action pass the tap to the delegate.
In your cellForItemAt() method, set the view controller as the delegate.
Now in your view controller handle the tap as desired.
Try this for Objective c
Add below code at cellForRowAtIndexPath
cell.btnOk.tag = indexPath.row ;
[cell.btnOk addTarget:self action:#selector(OkBtnAction:) forControlEvents:UIControlEventTouchUpInside] ;
Than add the action of that button
-(IBAction)OkBtnAction:(id)sender
{
UIButton* btn=(UIButton*)sender;
NSLog(#"row: %ld",(long)btn.tag);
}

How to callback a function in tableView's Class from tableViewCell's Class

I'm having a TableView. In that tableView, I custom it's cells
like this
In this cell I have 2 part. An Image and an TextField.
It's look like facebook's post status. When I click to Image, I want to open a new ViewController and the same for TextField
But I have a problem that I can't call segue from my cell's class file.
Are there any way that I can call a function in TableViewController's class from TableViewCell's class ?
I know that I can use delegate but I don't like this way a lot, because if I do this way I have to set a lot of delegate in my project.
Are there any better way to present a new ViewController directly from TableViewCell's class
Using a delegate is a very good way to solve your problem.
If you don't like that solution then you could design a table view cell that has a closure property set by the view controller, and invokes that closure when the button is pressed.
EDIT:
Another alternative is to leave the button action empty in your custom cell, but still connect up outlets to the buttons.
Then in your cellForRow(at:) method, install an IBAction that has your view controller as the target. (Credit to #SoanSani, who's answer is below)
In that IBAction method, you can use the coordinates of the button to figure out the indexPath of the cell hat contains the button that was tapped.
I've created an extension to UITableView that lets you figure out the cell that contains any view. The code is below:
import UIKit
public extension UITableView {
/**
This method returns the indexPath of the cell that contains the specified view
- Parameter view: The view to find.
- Returns: The indexPath of the cell containing the view, or nil if it can't be found
*/
func indexPathForView(_ view: UIView) -> IndexPath? {
let origin = view.bounds.origin
let viewOrigin = self.convert(origin, from: view)
let indexPath = self.indexPathForRow(at: viewOrigin)
return indexPath
}
}
You can use delegates, but if you dont want to use delegates
while setting up the cell add target to your button tableViewController class and then you can receive all events in tableview class rather than cell class.
But this would require to add tags which you can use to differentiate which button in cell was clicked
Objective C Code
[OkBtn addTarget:self action:#selector(okButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
Swift Code
OkBtn.addTarget(self, action: #selector(ViewController.okButtonTapped), for: .TouchUpInside)

Two clickable items in UITableView

I have a UITableview as a contact list in which there are a lot of users. It has a thumbnail photo and profile details on each row. I want to make it like when clicking on thumbnail, it goes another page for photo and when clicking on the rest of the space it goes to somewhere else. By using table view delegate I know which row is clicked and pass data, like user id to a new ViewController. But can I know which row when the thumbnail is clicked?
I am using the tag to find the view from cell, like
UIImageView *thumbnailView = (UIImageView *) [cell viewWithTag:1];
I think I cannot label the row index by tag.
You can add gesture to thumbnail image and get events on it. Need to set tag for thumb image as per indexPath.row.
Add following code in you in cell datasource method (cellForRowIndexPath:) :
cell.YOURIMGVIEW.userInteractionEnabled = YES;
cell.YOURIMGVIEW.tag = indexPath.row;
UITapGestureRecognizer *clickable = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(imageClicked:)];
clickable.numberOfTapsRequired = 1;
[cell.YOURIMGVIEW addGestureRecognizer:clickable];
[clickable release];
And also used below method :
-(void)imageClicked:(id)sender
{
UITapGestureRecognizer *gesture = (UITapGestureRecognizer *) sender;
NSLog(#"image tag is = %d", gesture.view.tag);
////////
You custome come goes Here !!!!!!!!!!!!!!
///////
}
You can use the photo as accessory view. Or use a UIButton with the photograph as background and set the action accordingly. (e.g. call a method on the view controller which then performs the push or segue. Doing so you will have to pass some data to the view controller indicating which row was actually clicked in. The number of the row can be used or you can set the tag of the button with some numeric id.)
Go the Easy way because doing it hard-way won't grant you a president award, right ?
Instead of UIImageView take a UIButton and set the Image on UIButton instance.
Set Button tag as the indexPath.row so that when you retrieve it you know which row is clicked. You can also sort it the other way but it seems quiet handy.
Add target into the button to a custom function. [ btnObj addTarget ...... ]
tyepcast you sender to a UIButton and receive the tag (indexpath.row)
You can remove all gesture recognizers and buttons in tableviewcell, and in your controller, you can implement below delegate;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
To make this method triggered, you need to set tableview delegate as your controller, either via code as below, or using storyboard.
- (void)viewDidLoad {
self.tableview.delegate = self;
}
By doing this, it won't matter which item you clicked in your cell, delegate method will be called always.
I hope this helps.

Custom UITableViewCell button click

In a UIViewController there is a UITableView which consists custom UITableViewCell with a UIButton.
When the user clicks the button (in the custom UITableViewCell), I want to display a message in the hosting UIViewController - what is the right way to achieve that? How should I notify the UIViewController that the button was clicked?
You should use delegation to tell the UIViewController that something happened in the cell.
I'm not exactly sure what kind of message you are referring to but if you mean a you want to show a popup just create a UIAlertView and show it when the button is clicked in the cell.
However, if you mean change a UIlabel text or whatever as a message on the ViewController you can always pass whatever you need to change into the TableView and Cell or the UIViewController itself into it.
I usually create a method on the custom cells class and pass it whatever I need into the custom TableView's constructor. Then in the TableView's GetCell() method pass whatever I need to change into that method I created on the cell and save it as a variable on the cell.
If you've initiated your UITableViewCell, and added a button to the cell, you can use a Delegate when the button is clicked, something like this:
UIButton button = new UIButton (cell.Bounds.X, cell.Bounds.y, cell.Bounds.Width, cell.Bounds.Height);
button.TouchUpInside += (object sender, EventArgs e) =>
{
label.text = "Blablabla";
};
Where the label is, is up to you. I hope this helps, good luck!

Custom UITableViewCell Button and RowSelected (iOS/Monotouch)

I have a 'Load More' UIButton inside a custom UITableViewCell. My table also uses a Delegate. I want to reload the table data when this button is clicked. I have noticed that when I click the button, nothing happens. But when I click on the area around the button i.e. the actual Cell, the Delegate gets the RowSelected event.
I tried using SetSelected(true,false); from the button's touch up inside event to see if it would fire the RowSelected event for the delegate, but it didn't.
Can anyone explain me how I can make a button click for a Custom Table cell fire the actual Row Selected event? If this isn't a viable option, is there a better way to 'Load more data' other than placing the button inside a custom table view cell?
Thanks!
UPDATE:
I do use ContentView.AddSubView as shown in the code below. Please note I'm using Monotouch, but the logic is the same:
public LoadMoreCell (string reuseCellIdentifier)
:base(UITableViewCellStyle.Default, reuseCellIdentifier)
{
SelectionStyle = UITableViewCellSelectionStyle.None;
_btnLoadMore = UIButton.FromType(UIButtonType.RoundedRect);
_btnLoadMore.Frame = new RectangleF(10,5,300,30);
_btnLoadMore.SetTitle("Load More", UIControlState.Normal);
_btnLoadMore.UserInteractionEnabled = true;
ContentView.AddSubview(_btnLoadMore);
}
I have a TableDelegate that has a RowSelected method where I reload the data...however, the RowSelected only gets fired when I click the actual row.
I think you might have added the uibutton as
[self addSubView:yourButton];
instead use :-
[self.contentView addSubview:yourButton];
and all the other controls of your custom cell.
Do this in the initializer of your custom cell :-
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {}
make a custom UITableViewDataSource for your table
and when you hit the button 'Load more', call a method of this datasource to add other data to the list of the datasource, add this datasource to your table and make sure to reload the data of the table
this.tblData.ReloadData ();

Resources