How to send data by clicking UITableViewCell's button to another ViewController - ios

I want to send data using a button click which is in uitableviewcell. I got the data from web service. Each row button send different data to viewController.
Attach cellForRowAtIndex Method below:
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath {
static NSString *identifier = #"CategoryCell";
NSDictionary *dictMenuData = [_arrHandMadeList objectAtIndex:indexPath.row];
CategoryCell *cell = (CategoryCell *)[tableView dequeueReusableCellWithIdentifier:identifier];
if(!cell) {
[tableView registerNib:[UINib nibWithNibName:#"CategoryCell" bundle:nil] forCellReuseIdentifier:identifier];
cell = (CategoryCell *)[tableView dequeueReusableCellWithIdentifier:identifier];
}
cell.btnShowRatingDetails.tag = indexPath.row;
[cell.btnShowRatingDetails addTarget:self action:#selector(showRatingClicked:) forControlEvents:UIControlEventTouchUpInside];
[arrReview removeAllObjects];
//arrReview = [dictMenuData objectForKey:#"RivewData"];
[arrReview addObjectsFromArray:[dictMenuData objectForKey:#"RivewData"]];
[cell setupHandMadeCell:dictMenuData];
return cell;
}
Method for button is below:
-(void) showRatingClicked:(UIButton*)sender {
//if (sender.tag == currentIndex) {
ReviewVC *rvc = (ReviewVC*)[self.storyboard instantiateViewControllerWithIdentifier:#"ReviewVC"];
rvc.arrReviewDetails = arrReview;
rvc.strRestaurentName = [dictMenuData objectForKey:#"Restaurant_Name"];
rvc.strRestaurentId = [dictMenuData objectForKey:#"Restaurant_Id"];
rvc.strRestaurentRating = [dictMenuData objectForKey:#"Stars"];
[self.navigationController pushViewController:rvc animated:YES];
//}
}
Please help me
Thanks in advance

You need to get the index of selected cell button. You can get it from sender.tag.
-(void) showRatingClicked:(UIButton*)sender {
ReviewVC *rvc = (ReviewVC*)[self.storyboard instantiateViewControllerWithIdentifier:#"ReviewVC"];
NSDictionary *dictMenuData = [_arrHandMadeList objectAtIndex:sender.tag];
rvc.arrReviewDetails = [dictMenuData objectForKey:#"RivewData"]; //or as per your data
rvc.strRestaurentName = [dictMenuData objectForKey:#"Restaurant_Name"];
rvc.strRestaurentId = [dictMenuData objectForKey:#"Restaurant_Id"];
rvc.strRestaurentRating = [dictMenuData objectForKey:#"Stars"];
[self.navigationController pushViewController:rvc animated:YES];
}
Once cell.btnShowRatingDetails.tag = indexPath.row; button is assigned the tag you can get the data object in the action method, same way you get it using indexpath.row.

You need to use NSDictionary *dictReview = [_arrHandMadeList objectAtIndex:sender.tag]; in -(void) showRatingClicked:(UIButton*)sender to get the appropriate dictionary, then use it at the place of dictMenuData.
Remove dictMenuData altogether from your code.

Related

Button in Cell and move View Controller

I want move to View Controller after click button in cell. I try it with using click button:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSInteger rowOfCell = [indexPath row];
TwoParramCell *cell = [tableView dequeueReusableCellWithIdentifier:#"TwoParramCell" forIndexPath:indexPath];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
NSDictionary *dic = [self.arrayGoodInfo objectAtIndex:indexPath.row];
cell.delegate = self;
if (rowOfCell == 0) {
cell.btnSearch.hidden = NO;
}
cell.btnSearch.tag = indexPath.row;
[cell.btnSearch addTarget:self action:#selector(searchBtnClicked:) forControlEvents:UIControlEventTouchUpInside];
cell.lblTitle.text = [dic objectForKey:#"stockModelName"];
cell.isMeterial = #"NO";
cell.txtContent.text = #"";
cell.txtContent.tag = indexPath.row;
if ([dic objectForKey:#"serial"]) {
cell.txtContent.text = [dic objectForKey:#"serial"];
}else{
cell.txtContent.text = #"";
}
return cell;}
Here is searchBtnClicked:
- (void)searchBtnClicked: (UIButton *) sender{
if (sender.tag == 0){
SearchSerialVC *searchVC = [[SearchSerialVC alloc] initWithNibName:#"SearchSerialVC" bundle:nil];
[self.navigationController pushViewController:searchVC animated:YES];
[VTService showToastWithText:#"Search Serial"];
}
}
Toast show but not push to Search Serial View Controller. What happen in here? Please, help me.
Step1. Comment out [VTService showToastWithText:#"Search Serial"];
Step2. Check self.navigationController
Step3. Check SearchSerialVC
self.navigationController may be is nil

Objective-C pass tableView indexPath to another method

I have this cellForRowAtIndexPath method here:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
if (cell.accessoryView == nil) {
cell.accessoryView = [[Checkbox alloc] initWithFrame:CGRectMake(0, 0, 25, 43)];
cell.accessoryView.opaque = NO;
cell.backgroundColor = [UIColor clearColor];
[(Checkbox*)cell.accessoryView addTarget:self action:#selector(checkBoxTapped:forEvent:) forControlEvents:UIControlEventValueChanged];
}
NSString *sectionTitle = [contactSectionTitles objectAtIndex:indexPath.section];
NSArray *sectionContacts = [contactDirectoryFinal objectForKey:sectionTitle];
NSString *contacts = [[sectionContacts objectAtIndex:indexPath.row] valueForKey:#"item"];
cell.textLabel.text = contacts;
[(Checkbox*)cell.accessoryView setChecked: [[[sectionContacts objectAtIndex:indexPath.row] valueForKey:#"checkedItem"] boolValue] ];
return cell;
}
inside this method, I have this line:
[(Checkbox*)cell.accessoryView addTarget:self action:#selector(checkBoxTapped:forEvent:) forControlEvents:UIControlEventValueChanged];
which calls this method
- (IBAction)checkBoxTapped:(id)sender forEvent:(UIEvent*)event
{
}
What I am trying to do is adjust the way this method is called so I am also passing int the indexPath.row number
I got started with this:
[(Checkbox*)cell.accessoryView addTarget:self action:#selector(checkBoxTapped:forEvent:rowNumber:) forControlEvents:UIControlEventValueChanged];
and this
- (IBAction)checkBoxTapped:(id)sender forEvent:(UIEvent*)event rowNumber:(int)row
{
}
but I am new to selectors, my question is where do I pass in the rowNumber?
As you've found out you can't pass just any values with your selector, only the sender and the event. This is why you need another way pass the row number.
One method is to use the tag property on your control and retrieve it with [sender tag], however this approach will fail if the table indexes are changed without cellForRowAtIndexPath being called. It also won't work for sectioned table views.
A more robust approach is to use the location of your view to calculate the correct row. UITableView has a convenient method to do this:
- (IBAction)checkBoxTapped:(id)sender forEvent:(UIEvent*)event {
CGPoint checkBoxPosition = [sender convertPoint:CGPointZero toView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:checkBoxPosition];
}
As an alternative to passing it in ....
func checkBoxTapped(sender: CheckBox, withEvent event: UIEvent) {
if let tap = event.allTouches()?.first {
let location = tap.locationInView(tableView)
let indexPath = tableView.indexPathForRowAtPoint(location)
..... do something
}
}
*Update
As #Maddy 's comment
Do not use tag to represent the indexPath. It fails if the table view allows any rows to be moved, inserted, or deleted
this is not a good answer.*
As CheckBox is a UIView you can set its tag in cellForRowAtIndexPath: and then check for it in checkBoxTapped:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
if (cell.accessoryView == nil) {
cell.accessoryView = [[Checkbox alloc] initWithFrame:CGRectMake(0, 0, 25, 43)];
cell.accessoryView.opaque = NO;
cell.backgroundColor = [UIColor clearColor];
[(Checkbox*)cell.accessoryView addTarget:self action:#selector(checkBoxTapped:forEvent:) forControlEvents:UIControlEventValueChanged];
}
NSString *sectionTitle = [contactSectionTitles objectAtIndex:indexPath.section];
NSArray *sectionContacts = [contactDirectoryFinal objectForKey:sectionTitle];
NSString *contacts = [[sectionContacts objectAtIndex:indexPath.row] valueForKey:#"item"];
cell.textLabel.text = contacts;
[(Checkbox*)cell.accessoryView setChecked: [[[sectionContacts objectAtIndex:indexPath.row] valueForKey:#"checkedItem"] boolValue] ];
// set the index to the tag.
cell.accessoryView.tag = indexPath.row
return cell;
}
- (IBAction)checkBoxTapped:(id)sender forEvent:(UIEvent*)event
{
// get the index from the tag value
NSInteger row = ((UIView *)sender).tag
}
You could use:
- (NSIndexPath *)indexPathForCell:(UITableViewCell *)cell
once you have the UITableViewCell object which can be accessed as sender.superview

MGSwipeTableCellDelegate : Not Working

This is driving me crazy.
I have implemented MGSwipeTableCell which shows three buttons on the left and one button on the right when it is swiped to the right and left respectively.
https://github.com/MortimerGoro/MGSwipeTableCell
But, I am not able to trigger the delegate methods when those buttons are pressed after swiping. Here is an excerpt of my code.
detailviewcontroller.h
#interface DetailViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, MGSwipeTableCellDelegate>
detailviewcontroller.m
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
DataStruct *showCredit;
static NSString *CellIdentifier = #"Credit_Cell";
MGSwipeTableCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
//cell = [[CreditCustomViewTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Credit_Cell"];
cell = [[MGSwipeTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Credit_Cell"];
}
cell.leftButtons = [self createLeftButtons:3];
cell.leftSwipeSettings.transition = MGSwipeTransition3D;
cell.rightButtons = [self createRightButtons:1];
cell.rightSwipeSettings.transition = MGSwipeTransition3D;
cell.delegate = self;
return cell;
}
-(NSArray*) swipeTableCell:(MGSwipeTableCell*) cell swipeButtonsForDirection:(MGSwipeDirection)direction
swipeSettings:(MGSwipeSettings*) swipeSettings expansionSettings:(MGSwipeExpansionSettings*) expansionSettings
{
NSIndexPath *myPath = [creditTableView indexPathForCell:cell];
NSLog(#"Pressed Credit last = %d", myPath.row);
...
}
My Objective : To get the indexpath.row in which the button is pressed after swiping. Can somebody put me into right direction?
Use tappedButtonAtIndex delegate method to get the indexpath of the that cell in which the button gets clicked.
-(BOOL) swipeTableCell:(MGSwipeTableCell*) celll tappedButtonAtIndex:(NSInteger)index direction:(MGSwipeDirection)direction fromExpansion:(BOOL) fromExpansion{
NSIndexPath *indexPath = [tableVw indexPathForCell:celll];
NSInteger rowOfTheCell = [indexPath row];
NSInteger sectionOfTheCell = [indexPath section];
NSLog(#"rowofthecell %ld", rowOfTheCell);
NSLog(#"sectionOfTheCell %ld", sectionOfTheCell);
return NO; // If you don't want to hide the cell.
}
There is callback method which work without delegate, you can try that
[MGSwipeButton buttonWithTitle:#"More" backgroundColor:[UIColor lightGrayColor] callback:^BOOL(MGSwipeTableCell *sender) {
NSLog(#"Convenience callback for swipe buttons!");
}]

Not selecting the correct object in UI table View Cell

I have an array of user displayed in a table view when pushing the send button the cell dosen't selected right object. It can be quit random:). How do i make send the object displayed on the selected cell?
This is how i send my message
- (void)sendMessage:(id)sender {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
PFObject *object = [self.objects objectAtIndex:indexPath.row];
self.SendToUsername = [object objectForKey:#"username"];
self.SendToName = [object objectForKey:#"name"];
}
And this is my cell, where the send button is located.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object
{
static NSString *simpleTableIdentifier = #"LampCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
UIButton *sendbutton = (UIButton*) [cell viewWithTag:105];
[sendbutton addTarget:self action:#selector(sendMessage:) forControlEvents:UIControlEventTouchUpInside];
return cell;
}
It is quite easy. Tableview itself provide method.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
variable=[array objectAtIndex:indexPath.row];
}
In "Variable" you have value which is selected. If your array is accessible in whole controller then you can save "indexPath.row" and use on click event of send button to fetch selected record.
tableView indexPathForSelectedCell will not give you the index path you are expecting in the action method of a button that is in a cell. The cell wasn't selected - you touched the button.
To get the index path of the row for that button, there are a couple of different methods.
My preferred method is to traverse the view hierarchy to find the cell that contains the button, and use that to get the index path. See this question for more info:
Button in custom cell in dynamic table: how to know which row in action method?
My answer from this question is as follows. You could add these two methods to a category on UITableViewController, or you could just add them to your view controller, if you like.
- (NSIndexPath *)indexPathForCellSubview:(UIView *)subview
{
if (subview) {
UITableViewCell *cell = [self tableViewCellForCellSubview:subview];
return [self.tableView indexPathForCell:cell];
}
return nil;
}
- (UITableViewCell *)tableViewCellForCellSubview:(UIView *)subview
{
if (subview) {
UIView *superView = subview.superview;
while (true) {
if (superView) {
if ([superView isKindOfClass:[UITableViewCell class]]) {
return (UITableViewCell *)superView;
}
superView = [superView superview];
} else {
return nil;
}
}
} else {
return nil;
}
}
You could then get the index path in your button action method like so:
NSIndexPath *indexPath = [self indexPathForCellSubview:sender];
You don't need to set the tag for buttons to get the indexpath. You can simply get it using this piece of code:
- (void)sendMessage:(id)sender {
UITableViewCell *clickedCell = (UITableViewCell *)[[sender superview] superview];
NSIndexPath *clickedButtonIndexPath = [self.tableView indexPathForCell:clickedCell];
PFObject *object = [self.objects objectAtIndex:indexPath.row];
self.SendToUsername = [object objectForKey:#"username"];
self.SendToName = [object objectForKey:#"name"];
}

How to get value of uiTextField created programmatically in a uiTableView?

I'm a beginner in iOS and I try to get the value of my uiTextField that I created programmatically.
So my problem is that I create a form in an UITableViewController with a .json file. I have created my form, but I don't know how I can get the different values.
In my cellForRowAtIndexPath I created my different elements (I have textFields, textFields with picker and uiswitch). When the user have finished to fill out the form, he click on a "save" button and it is here that I want to get my values.
If someone can help me and put some code for explain .... :) Thanks.
some of my code :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
NSString *cellValue = [self getItemName:indexPath.section and:indexPath.row];
cell.textLabel.text = cellValue;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
NSString *itemType=[self getItemType:indexPath.section and:indexPath.row];
NSLog(#"%#",itemType);
if ([itemType isEqualToString:#"text"]) {
UITextField *Reference = [self createTextField];
[cell.contentView addSubview:Reference];
}else if ([itemType isEqualToString:#"checkbox"]) {
UIView *checkbox = [self createCheckbox:indexPath.section and:indexPath.row];
[cell.contentView addSubview:checkbox];
}else if ([itemType isEqualToString:#"picker"]) {
UITextField *Reference = [self createPicker:indexPath.section and:indexPath.row];
[cell.contentView addSubview:Reference];
}else if ([itemType isEqualToString:#"datePicker"]) {
UITextField *Reference = [self createDatePicker];
[cell.contentView addSubview:Reference];
}
return cell;
}
it is here that i create dynamically the elements. For example an uixtField :
-(UITextField*)createTextField{
UITextField *Reference = [[UITextField alloc] initWithFrame:CGRectMake(200 , 10, 200, 40)];
Reference.layer.borderColor=[[UIColor blackColor]CGColor];
Reference.layer.borderWidth=1.0f;
Reference.textAlignment=NSTextAlignmentCenter;
Reference.tag=_tag;
_tag++;
return Reference;
}
http://hpics.li/04b98ca
here it is an example of that i obtained with my dynamical generation.
Use:
[textField setTag:(integer value)]
when you creating fields in cellForRow... method.
Then use in saveMethod this:
[[tableView cellForIndexPath:indexPath] viewWithTag:(integer value)]
for get concrete field of concrete cell.
if ([itemType isEqualToString:#"text"]) {
UITextField *Reference = [self createTextField];
[Reference setTag:1];
[cell.contentView addSubview:Reference];
}
-(void)saveMethod
{
NSString *string = [[[self.tableView cellForRowAtIndexPath:indexPath] viewwithTag:1] text];
}
You can create elements in the method cellForRowAtIndexPath for your cells if after you want to get info from them, because it will be very difficult to get it.
The best way is creating your custom UITableViewCell with all elements you want and after, in the method didSelectRowAtIndexPath to get the info of your elements.
The way I get an indexPath from a view is by checking the superview until I get the parent cell, then using -indexPathForCell:.
- (UITableViewCell *)cellForView:(UIView *)view
{
while (view != nil && ![view isKindOfClass:[UITableViewCell class]]) {
view = view.superview;
}
return (UITableViewCell *)view;
}
- (NSIndexPath *)indexPathForView:(UIView *)view
{
return [self.tableView indexPathForCell:[self cellForView:view]];
}
Overall, this solution will run into problems. Cells do not persist in a table view. As soon as the cell is off the screen it is recycled by the table view.
This means you should not attempt to store data in a cell. A cell is used to present data and get user input, but never store data. Data is meant to be stored in the table data source.
In addition, it means you need to be careful when adding subviews to a cell. As the cell get recycled, the views you added in it's previous use will still be in the cell. You will need to have a cleanup section to -tableView:cellForRowAtIndexPath: to remove all the views you previously added.
My recommendation is to subclass UITableViewCell. You can either have 4 subclasses, one for each JSON type you have, or have 1 subclass which can be instantiated with in the 4 different ways. In my example, I have 1 subclass that can be instantiated 4 different ways.
Keep the different types of cells differentiated by using different reuse identifiers.
Use target/actions and delegates to get input from the controls on the cell.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier = nil;
NSString *itemType=[self getItemType:indexPath.section and:indexPath.row];
NSLog(#"%#",itemType);
if ([itemType isEqualToString:#"text"]) {
cellIdentifier = #"TextCell";
} else if ([itemType isEqualToString:#"checkbox"]) {
cellIdentifier = #"CheckboxCell";
} else if ([itemType isEqualToString:#"picker"]) {
cellIdentifier = #"PickerCell";
} else if ([itemType isEqualToString:#"datePicker"]) {
cellIdentifier = #"DatePickerCell";
}
MyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
if ([cellIdentifier isEqualToString:#"TextCell"]) {
cell = [MyTableViewCell textCellWithIdentifier:cellIdentifier];
} else if ([cellIdentifier isEqualToString:#"CheckboxCell"]) {
cell = [MyTableViewCell checkboxCellWithIdentifier:cellIdentifier];
} else if ([cellIdentifier isEqualToString:#"PickerCell"]) {
cell = [MyTableViewCell pickerCellWithIdentifier:cellIdentifier];
} else if ([cellIdentifier isEqualToString:#"DatePickerCell"]) {
cell = [MyTableViewCell datePickerCellWithIdentifier:cellIdentifier];
}
}
NSString *itemName = [self getItemName:indexPath.section and:indexPath.row];
cell.textLabel.text = itemName;
if ([itemType isEqualToString:#"text"]) {
NSString *itemValue = [self getItemValue:indexPath.section and:indexPath.row];
cell.textField.text = itemValue;
} else if ([itemType isEqualToString:#"checkbox"]) {
BOOL itemChecked = [self getItemChecked:indexPath.section and:indexPath.row];
cell.checkbox.selected = itemChecked;
} else if ([itemType isEqualToString:#"picker"]) {
NSString *itemValue = [self getItemValue:indexPath.section and:indexPath.row];
cell.pickerLabel = itemValue;
} else if ([itemType isEqualToString:#"datePicker"]) {
NSDate *itemDate = [self getItemDate:indexPath.section and:indexPath.row];
cell.datePickerLabel = itemDate;
}
return cell;
}
For my problem, I have create a NSMutableDictionaryin which i put my element like that :
key : "name"
value : "UITextField"
Like that i can get the textField everywhere in my class.
in .h file
create the dictionary
in .m
just put the element and when you want to go the text value do :
UITextField* myTextField= [dictionnary objectForKey:key];

Resources