I have button in UITableView if user select the button then it have to go NextViewController [with carry of some JSON values].
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
orderid=[NSString stringWithFormat:#"%#",[[arrDictionary objectAtIndex:indexPath.row]objectForKey:#"orderid"]];
NSLog(#"orderid==%#",orderid);
}
I can easily get the values from the selected cell
I have button in UITableViewCell so i need to get the button click is from which row?
I tried with this code but its only display first orderid i have stored
-(void)nextview:(UIButton *)button
{
NSIndexPath *index=[tableview indexPathsForSelectedRows];
orderid=[NSString stringWithFormat:#"%#",[[arrDictionary objectAtIndex:index]objectForKey:#"orderid"]];
NSLog(#"orderid==%#",orderid);
}
If you have not working with multiple selection then you can get one row which is selected by :
NSIndexPath *index = [tableview indexPathForSelectedRow];
If you have multi row selection then :
You will get the array of selected NSIndexPath of selected index as like :
NSArray *selectedIndexPaths = [tableview indexPathsForSelectedRows];
You can run loop up to the selectedIndexPaths.count and get selected rows data.
DOCUMENT :
// Selection
- (NSIndexPath *)indexPathForSelectedRow;
// returns nil or index path representing section and row of selection.
- (NSArray *)indexPathsForSelectedRows NS_AVAILABLE_IOS(5_0);
// returns nil or a set of index paths representing the sections and rows of the selection.
you can get selected cell as
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:[self.tableView indexPathForSelectedRow]];
and indexPath as [self.tableView indexPathForSelectedRow]
and I think you'll then pefror a segue
[self perfromSegueWithIdentifier:#"Segue"];
For Push json to NextViewController
-(void)YouButtonSelector:(UIButton *)sender{
NextViewController *rightController=[[NextViewController alloc] init];
rightController.eventIdIs=self.event_id;
rightController.PreviousJson=PresentJson;
rightController.hidesBottomBarWhenPushed=YES;
[self.navigationController pushViewController:rightController animated:YES];
}
For Button Clicked
[cell.checkboxBtn setTag:indexPath.row];
[cell.checkboxBtn addTarget:self action:#selector(nextview:) forControlEvents:UIControlEventTouchUpInside];
-(void)nextview:(UIButton *)button
{
NSLog(#"Button select is :%d",button.tag);
}
1 - You can give button tag in cellForRowAtIndexPath method
button.tag = indexPath.row;
2 - you have receive you orderid
-(void)nextview:(UIButton *)button
{
NSString *orderid=[NSString stringWithFormat:#"%#",[[arrDictionary objectAtIndex:button.tag] objectForKey:#"orderid"]];
NSLog(#"orderid==%#",orderid);
}
Assign
cell.btn.tag = indexPath.row;
and on button press function get data from array using
UIButton *btn = (UIButton *)sender;
NSString *str = arrDictionary[btn.tag];
Related
Im using UITableView with checkboxes. In my cellForRowAtIndexPath method, I have set selected few cells as follows,
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if(tableView == self.sideBarTbl){
cell.textLabel.text = [titleArray objectAtIndex:indexPath.row];
cell.tag = indexPath.row;
if(indexPath.row == 0){
[cell setSelected:true];
}else if(indexPath.row == 1){
[cell setSelected:true];
}else {
[cell setSelected:false];
}
}
In short, if the row is 0,1 then Im checking the checkboxes of the UITableView.
when the user clicks the row 0 or row 1, it should call didDeselectRowAtIndexPath since row 0 and row 1 checkmarks are already checked. But, it is always calling the didSelectRowAtIndexPath. no matter if the checkbox is checked or not, it always calls the didSelectRowAtIndexPath. How can I let it call didDeselectRowAtIndexPath when the checkbox is checked and call didSelectRowAtIndexPath when the checkbox is not checked?
didDeselectRowAtIndexPath method will only be called for cells which has been touched to select before. It's not related to the cell's selected property. If you want to do something for deselected cells, just record the selection manually in NSMutableArray with didSelectRowAtIndexPath method. Forget the didDeselectRowAtIndexPath. For reference: UITableView cell on double click should go to previous state
And an Objective-C example:
#interface SomeViewController : UIViewController<UITableViewDelegate> {
NSMutableArray *selectedIndexPaths;
}
#implementation SomeViewController
//......
- (void)viewDidLoad {
[super viewDidLoad];
selectedIndexPaths = [NSMutableArray array];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if ([selectedIndexPaths containsObject:indexPath]) {
[selectedIndexPaths removeObject:indexPath];
//Do something when deselecting.
}
else{
[selectedIndexPaths addObject:indexPath];
//Do something when selecting.
}
}
//......
#end
If the selection is single and exclusive, like a radiobox, just use single variable NSIndexPath *selectedIndexPath; to record selection in didSelectRowAtIndexPath, after handling the deselecting process for previous selected cell.
Use the following code in your cellForRowAtIndexPath instead of [cell setSelected:true];
[tableView selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionBottom];`
Use the following code when the user wants to deselect. Use it in your didDeselectRowAtIndexPath
[tableView deselectRowAtIndexPath:indexPath animated:YES];
Finally, you can get the selected indexes as follows,
-(void) getSelectedIndices
{
NSArray *indexPathArray = [tableView indexPathsForSelectedRows];
for(NSIndexPath *index in indexPathArray)
{
NSLog(#"Index: %ld",(long)index.row);
}
}
Revert back in case if you have any queries
I have a textField on custom cell in a tableView. When one of the cell is selected I am able to disable textField for that particular cell by using set selected method.
(void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
if (selected) {
self.accountNameTxtField.enabled = NO;
} else {
self.accountNameTxtField.enabled = YES;
}
}
The requirement is to disable textField for other cells when any one of the cell is selected. Please guide me on this, Thanks.
You have to use instance variable, you could use indexPath.
When user select any cell, set value of that instance variable to selected indexPath.
And reloadTable.
In cellForRowAtIndexPath check if current indexPath is selected indexPath, if yes enable textField else disable it.
Create button on tableview cell and enable or disable textfield on tableview or can apply this logic on tableview didSelectRowAtIndexPath
-(void) btnClick:(id)sender
{
UIButton *btn = (UIButton *)sender;
CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:tblView];
NSIndexPath *indexPath = [tblView indexPathForRowAtPoint:buttonPosition];
NSLog(#"table view row is ----%ld",indexPath.row);
if (btn.isSelected == false)
{
[btn setSelected:true];
[selectRow addObject:[NSString stringWithFormat:#"%ld",indexPath.row]];
self.accountNameTxtField.enabled = yes;
//selectRow is NSMutableArray
}
else
{ [btn setSelected:false];
[selectRow removeObject:[NSString stringWithFormat:#"%ld",indexPath.row]];
self.accountNameTxtField.enabled = no;
}
}
[tbleview relaoddata];
if ([selectRow containsObject:[NSString stringWithFormat:#"%ld",indexPath.row]])
{
accountNameTxtField.enabled = yes;
}
else
{
accountNameTxtField.enabled = NO;
}
Use your Data to do this, you must be having some data in for of array containing dictionaries, or class object, I am demonstrating Class Object.
Say you have a Class object DataClass create a BOOL property say textFieldSelected, now follow the steps
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"TableViewCell" forIndexPath:indexPath];
DataClass *object=[self.dataArray objectAtIndex:indexPath.row];
[cell.textField setTag:indexPath.row];
cell.textField.delegate=self;
cell.textField.enabled=object.textFieldSelected;
return cell;
}
Now when you select a row
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
for(DataClass *object in self.dataArray){
object.textFieldSelected=NO;
}
DataClass *object=[self.dataArray objectAtIndex:indexPath.row];
object.textFieldSelected=YES;
[tableView reloadData];
}
Initially you can set textFieldSelected=YES; so that all the textFields are enabled. You can wish to play with object and it will work that way. All the best.
Finally i managed to find the solution with integer cell selection count.
cell selection count gets increased in will select row at index path method and set that value in NsuserDefaults.
selectedIndex++;
NSString *valueToSave = [NSString stringWithFormat:#"%ld",(long)selectedIndex];
[[NSUserDefaults standardUserDefaults] setObject:valueToSave forKey:#"SelectedIndexString"];
[[NSUserDefaults standardUserDefaults] synchronize];
cell selection count gets decreased in didDeselectRowAtIndexPath method and set that value in NsuserDefaults.
selectedIndex--;
In my custom table view cell class in textFieldDidBeginEditing method get the stored value from NsUserDefaults and act upon.
NSString *SelectedIndexString = [[NSUserDefaults standardUserDefaults]
stringForKey:#"SelectedIndexString"];
NSLog(#"%ld",(long)SelectedIndexString);
NSInteger SelectedIndexCount = [SelectedIndexString integerValue];
if (SelectedIndexCount) {
self.accountNameTxtField.enabled = NO;
}
else{
self.accountNameTxtField.enabled = YES;
}
Thanks you so much guys. Thanks for your time.
I’m building an iOS app using storyboards.I have used UITableViewController which has 6 custom cells each of which contains three IBOutlet buttons and one IBOutlet label.
When the user clicks on any button in one particular custom cell, then the value of only that particular cell label should change.
But what happens is, values of all labels in each custom cell get changed.
Here is my code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *Cellidentifier1 = #"List";
Cell *cell1 = [tableView dequeueReusableCellWithIdentifier:Cellidentifier1 forIndexPath:indexPath];
cell1.selectionStyle = UITableViewCellSelectionStyleNone;
// Configure the cell...
long row = [indexPath row];
cell1.First.tag=row;//button iboutlet in cell
cell1.Second.tag=row;//button iboutlet in cell
cell1.Third.tag=row;//button iboutlet in cell
cell1.Level.tag=row;
cell1.Level.text=Skill;//label iboutlet in cell
return cell1;
}
-(IBAction)FirstAction:(id)sender{
Skill=#"first";
[self.tableView reloadData];
}
-(IBAction)SecondAction:(id)sender{
Skill=#"Second";
[self.tableView reloadData];
}
-(IBAction)ThirdAction:(id)sender{
Skill=#"Third";
[self.tableView reloadData];
}
A couple of issues:
You should have a model that reflects what's in your table view. Specifically, right now you have a single Skill value, but you have six rows. You want to maintain a model that is an array of values, something like:
#property (nonatomic, strong) NSMutableArray *values;
And
- (void)viewDidLoad {
[super viewDidLoad];
self.values = [#[#"first", #"first", #"first", #"first", #"first", #"first"] mutableCopy];
}
And
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *Cellidentifier1 = #"List";
Cell *cell = [tableView dequeueReusableCellWithIdentifier:Cellidentifier1 forIndexPath:indexPath];
NSString *value = self.values[indexPath.row];
cell.level.text = value;
return cell;
}
Note, no tag numbers needed.
When you tap on a button you must (a) identify what row in the table that corresponds to; (b) update that row in your model; and (c) reload that single row in the table (which will look up the value in the model):
- (void)updateCell:(UIView *)cell withValue:(NSString *)value {
NSParameterAssert(cell);
NSIndexPath *indexPath = [self.tableView indexPathForCell:(UITableViewCell *)cell];
if (cell) {
self.values[indexPath.row] = value;
[self.tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
- (IBAction)didTapFirstButton:(id)sender {
[self updateCell:[[sender superview] superview] withValue:#"first"];
}
- (IBAction)didTapSecondButton:(id)sender{
[self updateCell:[[sender superview] superview] withValue:#"second"];
}
- (IBAction)didTapThirdButton:(id)sender{
[self updateCell:[[sender superview] superview] withValue:#"third"];
}
Note, the sender is the button. So I get the table view cell by grabbing the superview (which is the cell's content view) and then grab its superview (the cell itself). If your view hierarchy is different, then change that as appropriate, but hopefully this illustrates the idea.
First you have to do is that use delegate method selectRowAtIndexPath when the row is selected then the indexPath selected row buttons can be used...
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
}
when the row is selected then that desired rows button functions will be performed
Try below code.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *Cellidentifier1 = #"List";
Cell *cell1 = [tableView dequeueReusableCellWithIdentifier:Cellidentifier1 forIndexPath:indexPath];
cell1.selectionStyle = UITableViewCellSelectionStyleNone;
// Configure the cell...
long row = [indexPath row];
cell1.First.tag=row;//button iboutlet in cell
cell1.Second.tag=row;//button iboutlet in cell
cell1.Third.tag=row;//button iboutlet in cell
cell1.Level.tag=row;
cell1.Level.text=Skill;//label iboutlet in cell
[cell1.First addTarget:self action:#selector(FirstAction:) forControlEvents:UIControlEventTouchUpInside];
[cell1.Second addTarget:self action:#selector(SecondAction:) forControlEvents:UIControlEventTouchUpInside];
[cell1.Third addTarget:self action:#selector(ThirdAction:) forControlEvents:UIControlEventTouchUpInside];
return cell1;
}
In your IBOutlet methods add this to find the indexPath for the row
CGPoint hitPoint = [sender convertPoint:CGPointZero toView:self.tableView];
NSIndexPath *hitIndex = [self.tableView indexPathForRowAtPoint:hitPoint];
instead of reloading the entire tableview you only want to reload the text for that cell at that specified indexPath
To reload only one cell, do this instead of [self.tableView reloadData];
[self.tableView reloadRowsAtIndexPaths:#[hitIndex] withRowAnimation:UITableViewRowAnimationNone];
There's a few ways to do it. But, from looking at your code I would make sure you get the right indexPath from the cell you selected. Assuming you have the target action already set up, you could rewrite your IBAction method like so:
-(IBAction)firstAction:(UIButton *)sender{
int row = sender.tag;
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:row inSection:0];
Cell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
Skill = #"first";
[self.tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationNone];
}
this is going to get the right cell and index path. Update that cell's label only and then reload it.
I understand this is suppose to happen but I haven't been able to find a way to call this method when the button is tapped The method gets called but the wrong cell is selected.
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object{
_postCell = (postCell *) [self.tableView dequeueReusableCellWithIdentifier:#"postCell"];
_postCell.personStringPost.text = [object objectForKey:#"stringPost"];
[_postCell.nameLabel setTitle:[object objectForKey:#"User_Name"] forState:UIControlStateNormal];
_postCell.userId = [object objectForKey:#"userId"];
_postCell.selectionStyle = UITableViewCellSelectionStyleNone;
PFFile *imageFile = [object objectForKey:#"profileImage"];
NSData *data = [imageFile getData];
_postCell.profileImage.image = [UIImage imageWithData:data];
[_postCell.nameLabel addTarget:self action:#selector(personProfile:tableView:) forControlEvents: UIControlEventTouchUpInside];
[_postCell.profileImageButton addTarget:self action:#selector(personProfile:tableView:) forControlEvents:UIControlEventTouchUpInside];
return _postCell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[super tableView:tableView didSelectRowAtIndexPath:indexPath];
postCell *cell = (postCell *)[tableView cellForRowAtIndexPath:indexPath];
self.userId = cell.userId;
NSLog(#"Did Select: %#", self.userId);
}
- (void) personProfile: (NSIndexPath *) indexPath tableView: (UITableView *) tableView{
[self tableView:tableView didSelectRowAtIndexPath:indexPath];
[self performSegueWithIdentifier:#"personProfile" sender:self];
}
Few things i hope it will help
while dealing with button with only one section
in cellfor row method
yourcell.mybutton.tag=indexPath.row;
-(void)myCellbuttonAction:(id)sender
{
UIButton *button = (UIButton *)sender; // first, cast the sender to UIButton
NSInteger row = button.tag; // recover the row
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:0];
// apply your logic for indexpath as in didselect row
}
While dealing with multiple sections and multiple rows it this might help you
in cell for row method
yourcell.tag=indexPath.section;
yourcell.contentview.tag=indexPath.row;
and your button action might look like this
-(void)myCellbuttonAction:(id)sender
{
UIButton *button = (UIButton *)sender; // first, cast the sender to UIButton
id rowid =[button superview];
id sectionid = [rwoid superview];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[rowid tag] inSection:[sectionid tag]];
// apply your logic for indexpath as in didselect row
}
A few things here.
a) I would not use an instance variable (_postCell) in your cellForRowAtIndex method. You will likely have cell re-use problems and this may well be the source of your error. Replace it with a local variable:
postcell *cell = (postCell *)[self.tableView dequeueReusableCellWithIdentifier:#"postCell"];
You will also need to replace all references to _postCell with cell.
b) Note that in the same line your cast uses lowercase = (postCell *)... - I have done the same above, but it is best practice for class names to start with capital letters.
c) You have a property named nameLabel, which suggests its a UILabel, but you are using the setTitle:forState: method, which implies it's a UIButton. I would rename this property since debugging will be a lot easier if the names match the classes (or at least don't imply the wrong class).
d) When you call the addTarget:action:forControlEvents method, your selector is for personProfile:tableView:. The signature for that method is for an NSIndexPath and a UITableView. But your button will not be sending those arguments of those types. It will send details of the sender - i.e. the button which triggered the action. So you need to revise your method to accept arguments of that type:
[cell.nameLabel addTarget:self action:#selector(buttonPressed:) forControlEvents: UIControlEventTouchUpInside];
e) When the method gets called, you need a way to determine which cell the sending button was on. Ideally you would subclass UIButton to add some link to the cell, but (if you have only one section) you might get away with putting the row number as a tag. To do this add:
cell.nameLabel.tag = indexPath.row;
to your cellForRowAtIndexPath:. Then you can implement a different method to handle the button press, as follows:
-(void)buttonPressed:(id)sender {
UIButton *button = (UIButton *)sender; // first, cast the sender to UIButton
NSInteger row = button.tag; // recover the row
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:0]; // derive the indexPath, assuming section is 0
[self.tableView selectRowAtIndexPath:indexPath animated:YES]; // select the relevant row in the table (assuming the table is self.tableView)
[self performSegueWithIdentifier:#"personProfile" sender:self]; // perform the segue
}
f) Note in the above that you should not call tableView:didSelectRowAtIndexPath:. This is for the tableView to call when the user selects the row, not for selecting rows programmatically. Use selectRowAtIndexPath:animated: instead.
This is basically pbasdf answer above with Swift 3
I do call didSelectRowAt directly since it is not triggered by selectRowAtIndexPath
The tag is set on cell creation with the row of the indexpath
The getTableView function is my own
#IBAction func actionButtonPushed(_ sender: Any) {
guard let button = sender as? UIButton else { return }
guard let tableView = getTableView() else { return }
let indexPath = IndexPath(row: button.tag, section: 0)
tableView.selectRow(at: indexPath, animated: false, scrollPosition: .none)
if let delegate = tableView.delegate {
delegate.tableView!(tableView, didSelectRowAt: indexPath)
}
}
I am using a tableView which loads a custom UITableViewCell with a "Tap" button inside it. A method is called when user clicks the button.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{...
[btnRowTap addTarget:self action:#selector(didButtonTouchUpInside:) forControlEvents:UIControlEventTouchDown];
...
return cell;
}
In the didButtonTouchUpInside method, Im trying to retrieve the value of row selected in the following way:
-(IBAction)didButtonTouchUpInside:(id)sender{
UIButton *btn = (UIButton *) sender;
UITableViewCell *cell = (UITableViewCell *)btn.superview;
NSIndexPath *indexPath = [matchingCustTable indexPathForCell:cell];
NSLog(#"%d",indexPath.row);
}
The problem is that on clicking button at any row, I am getting the same value of 0 every time.
Where am I going wrong?
You must NOT rely on the view hierarchy of a UITableViewCell. This approach will fail in iOS7, because iOS7 changes the view hierarchy of the cell. There will be an additional view between your button and the UITableViewCell.
There are better ways to handle this.
Convert the button frame so it is relative to the tableview
ask the tableView for the indexPath at the origin of the new frame
.
-(IBAction)didButtonTouchUpInside:(id)sender{
UIButton *btn = (UIButton *) sender;
CGRect buttonFrameInTableView = [btn convertRect:btn.bounds toView:matchingCustTable];
NSIndexPath *indexPath = [matchingCustTable indexPathForRowAtPoint:buttonFrameInTableView.origin];
NSLog(#"%d",indexPath.row);
}
set Button tag in to cellForRowAtIndexPath method Befor setting Method like
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{...
btnRowTap.tag=indexPath.row
[btnRowTap addTarget:self action:#selector(didButtonTouchUpInside:) forControlEvents:UIControlEventTouchDown];
...
return cell;
}
and your tapped cell getting like this:-
-(IBAction)didButtonTouchUpInside:(id)sender{
{
UIButton *button = (UIButton*)sender;
NSIndexPath *indPath = [NSIndexPath indexPathForRow:button.tag inSection:0];
//Type cast it to CustomCell
UITableViewCell *cell = (UITableViewCell*)[tblView1 cellForRowAtIndexPath:indPath];
NSLog(#"%d",indPath.row);
}
try like this,if you are adding button to cell content view then use below code.
UITableViewCell *buttonCell = (UITableViewCell *)sender.superview.superview;
UITableView* table1 = (UITableView *)[buttonCell superview];
NSIndexPath* pathOfTheCell = [table1 indexPathForCell:buttonCell];
int rowOfTheCell = [pathOfTheCell row];
int sectionOfTheCell = [pathOfTheCell section];
btn.superview is contentView of UITableviewCell. Use btn.superview.superview instead.
if you already knew the value inside the cell, then
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *currentCell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
if ([currentCell.textLabel.text isEqualToString:#"Your Cell Text value" ]){
//Do theStuff here
}
}
here is the code for your ibAction.you dont need to set any tag or anything else
-(IBAction)didButtonTouchUpInside:(id)sender{
NSIndexPath *indexPath =
[tbl
indexPathForCell:(UITableViewCell *)[[sender superview] superview]];
}