MGSwipeTableCellDelegate : Not Working - ios

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!");
}]

Related

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

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.

Wrong indexPath.row after reloadData

I'm trying to get the indexPath.row of a button clicked inside a tableView row.
When the user clicks this button I get the index.row corresponding to the button very well, but when I add more objects to the source array to create more cells by calling reloadData, the rowButtonClicked in each cell it's no longer giving me the correct indexPath.row in example I press the index 20 and now the printed indexPath.row is 9.
In cellForRowAtIndexPath to add the event to the button:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
lBtnWithAction = [[UIButton alloc] initWithFrame:CGRectMake(liLight1Xcord + 23, 10, liLight1Width + 5, liLight1Height + 25)];
lBtnWithAction.tag = ROW_BUTTON_ACTION;
lBtnWithAction.titleLabel.font = luiFontCheckmark;
lBtnWithAction.tintColor = [UIColor blackColor];
lBtnWithAction.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
[cell.contentView addSubview:lBtnWithAction];
}
else
{
lBtnWithAction = (UIButton *)[cell.contentView viewWithTag:ROW_BUTTON_ACTION];
}
//Set the tag
lBtnWithAction.tag = indexPath.row;
//Add the click event to the button inside a row
[lBtnWithAction addTarget:self action:#selector(rowButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
return cell;
}
To do something with the clicked index:
-(void)rowButtonClicked:(UIButton*)sender
{
//Get the index of the clicked button
NSLog(#"%li", (long)sender.tag);
[self doSomething:(long)sender.tag];
}
Constants.h
#define ROW_BUTTON_ACTION 9
Why it is giving an incorrect index when I change the initial items of the tableView? Is there a way to solve this issue?
It looks like you're messing up button tags. Once you set the tag
lBtnWithAction.tag = indexPath.row;
you won't be able to get button correctly with
lBtnWithAction = (UIButton *)[cell.contentView viewWithTag:ROW_BUTTON_ACTION];
(assuming ROW_BUTTON_ACTION is a constant). lBtnWithAction will be nil all the time except when indexPath.row is equal to ROW_BUTTON_ACTION.
I would propose to subclass UITableViewCell, add a button-property there and then just refer to it directly instead of searching by tag. In this case you'll be able to use tags for buttons freely :) –
#interface UIMyTableViewCell : UITableViewCell
#property (nonatomic, strong, nonnull) UIButton *lBtnWithAction;
#end
And then in cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UIMyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UIMyTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
[cell.lBtnWithAction addTarget:self action:#selector(rowButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
}
cell.lBtnWithAction.tag = indexPath.row;
return cell;
}
You can simply update you line -
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
to
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]
My take on this will be subclassing the UITableViewCell and providing a delegate for it to respond.
code:
//MyCoolTablewViewCell.h
#protocol MyCoolProtocol<NSObject>
-(void)youTouchedMyCoolCell:(MyCoolTableViewCell __nonnull *)myCoolCell;
#end
#interface MyCoolTableViewCell:UITableViewCell
#property(nonatomic, weak,nullable) id<MyCoolProtocol>myCooldelegate;
#end
//MyCoolTablewViewCell.m
#interface MyCoolTableViewCell(){
UIButton *mySuperCoolButton;
}
#end
#implementation MyCoolTablewViewCell
-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
if(!(self = [super initWithStyle:style reuseIdentifier:reuseIdentifier])){
return nil;
}
// init your stuff here
// init button
mySuperCoolButton = [UIBUtton buttonWithType:UIButtonTypeCustom];
[mySuperCoolButton addTarget:self action:#selector(tappedMyCoolButton:) forControlEvents:UIControlEventTouchUpInside];
return self;
}
- (void)tappedMyCoolButton:(id)sender{
if([_myCoolDelegate respondToSelector:#selector(youTouchedMyCoolCell:)]){
[_myCoolDelegate youTouchedMyCoolCell:self];
}
}
#end
then in your controller
// whatEverController.m
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// get the cell
cell = [tableView dequeueReusableCellWithIdentifier:#"myCoolIdentifier"forIndexPath:indexPath];
cell.myCooldelegate = self;
}
-(void)youTouchedMyCoolCell:(MyCoolTableViewCell *)myCoolCell{
NSIndexPath *myCoolIndexPath = [_tableView indexPathForCell:myCoolCell];
// then do whatever you want with the index path
}

IOS: How to prevent a view from getting opened in all cells

I have a rate button. Upon clicking on that button a view containing 5 stars opens. But when I click on rate button of particular cell, particular view opens but some views of other cells also get opens. I want the view containing 5 stars of that particular view only to get opened.
I am attaching the code of that view.
cv = [[ASStarRatingView alloc]initWithFrame:CGRectMake(190, y-5, 140, 30)]; //creat an instance of your custom view
cv.tag = indexPath.row ;
if([delegate.constants.snsrate[indexPath.row] isEqualToString: #"0"])
{
cv.hidden=TRUE;
}
else
{
cv.hidden=FALSE;
}
delegate.constants.selected=1;
[cell addSubview:cv];
And my code to close and open the view.
-(void)Rate_Comment:(UIButton *)sender
{
UIButton *b = (UIButton *)sender;
NSInteger row = b.tag ;
for(int i=0;i<[delegate.constants.snsrate count];i++)
delegate.constants.snsrate[i]= #"0";
delegate.constants.buttontag = row;
UITableViewCell *buttonCell = (UITableViewCell *)[b superview];
UITableView* table = (UITableView *)[buttonCell superview];
NSIndexPath* pathOfTheCell = [table indexPathForCell:buttonCell];
delegate.constants.snsIndexPath = pathOfTheCell;
if(![delegate.constants.user_id isEqualToString:[delegate.constants.snsCreatedBy objectAtIndex:row]])
{
if([[delegate.constants.snstotalrating_count objectAtIndex:row] isEqualToString:#"0"])
{
if(cv.hidden)
{
delegate.constants.snsrate[row]= #"1";
cv.hidden=FALSE;
}
else{
delegate.constants.snsrate[row]= #"0";
cv.hidden=TRUE;
}
[streamTable reloadRowsAtIndexPaths:#[pathOfTheCell] withRowAnimation:UITableViewRowAnimationNone];
}else
{
if(cv.hidden==FALSE)
cv.hidden=TRUE;
}
}
}
I am new to IOS. Please if anyone can help it will be much appreciated.
Thank you in advance.
I assume every cell has a "rate" button and a target method, like this:
// --------------------------------------------------------------------
// Sorry, I'm typing from memory, these code might not be 100% correct
// --------------------------------------------------------------------
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellID = #"cell";
MyCustomCell *cell = [tableView dequeueReusableCellForIdentifier:cellID];
if(cell == nil)
{
cell = [[MyCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
// --------------------------------------------------------
// Add the method to execute when tapping on a button
// --------------------------------------------------------
[cell.btnRate addTarget:self action:#selector(showRateControl:) forControlEvent:UIControlEventTouchUpInside];
}
// self.selectedRow should init with -1, since we don't want to show stars
// for the first row if self.selectedRow defaults to 0
if(self.selectedRow == indexPath.row)
{
cell.starsView.alpha = 1;
cell.btnRate.alpha = 0;
}
else
{
cell.starsView.alpha = 0;
cell.btnRate.alpha = 1;
}
return cell;
}
-(void)showRateControl:(id)sender
{
UIButton *rateButton = (UIButton *)sender;
// finding the row which the rate button was tapped
CGPoint rootPoint = [rateButton convertPoint:CGPointZero inView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:rootPoint];
// ------------------------------------------------------------
// here we record the row which the rate button was tapped
// in a property we declared in the .h file (see below)
// ------------------------------------------------------------
self.selectedRow = indexPath.row;
// refresh just the selected row (you could alternatively use self.tableView reloadData)
[self.tableView reloadRowsAtIndexPath:#[indexPath]];
}
In your header file, you can declare your selectedRow property like this:
...
class MyViewController: UIViewController
{
}
#property (nonatomic, assign) NSInteger selectedRow;
#end
In your implementation file's viewDidLoad, don't forget to initialise self.selectedRow to -1:
-(void)viewDidLoad
{
[super viewDidLoad];
...
self.selectedRow = -1;
}
See if that helps.

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"];
}

Radio button logic in UItableViewCells

Hey I'm working on a screen where user have option groups for example "Drink" which is title of section in my tableView, and their choices are "7up", "coke", etc which are cells of my table.
Now every Option Group choice (every cell in order words) has one radio button. I want to implement this. I'm facing problem if user selects any cell's radio button then other radio buttons should be deselected but how?
any help please
You should create a function to check your radio button from your custom cell and implements a delegate method to inform your TableViewController that your button on that cell was selected.
Your TableViewController needs to implements that delegate (dont forget to set each cell.delegate = self).
Then in your delegate method you create a loop to uncheck all of the radio buttons of the cells in the section except the cell you just checked.
Something like that :
This is a custom UITableViewCell with a button.
The images checked and uncheck need to look like a radio button checked and uncheked
Here is the .h file :
//RadioCell.h
#protocol RadioCellDelegate <NSObject>
-(void) myRadioCellDelegateDidCheckRadioButton:(RadioCell*)checkedCell;
#end
#interface RadioCell : UITableViewCell
-(void) unCheckRadio;
#property (nonatomic, weak) id <RadioCellDelegate> delegate;
#end
This is the .m file of RadioCell
//RadioCell.m
#property (nonatomic, assign) UIButton myRadio;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString*)reuseIdentifier
_myRadio = [UIButton buttonWithType:UIButtonTypeCustom];
[_myRadio setImage:[UIImage imageNamed:#"uncheck"] forState:UIControlStateNormal];
[_myRadio setImage:[UIImage imageNamed:#"check"] UIControlStateSelected];
[_myRadio addTarget:self action:#selector(radioTouched)orControlEvents:UIControlEventTouchUpInside];
_myRadio.isSelected = NO;
//don't forget to set _myRadio frame
[self addSubview:_myRadio];
}
-(void) checkRadio {
_myradio.isSelected = YES;
}
-(void) unCheckRadio {
_myradio.isSelected = NO;
}
-(void) radioTouched {
if(_myradio.isSelected == YES) {
return;
}
else {
[self checkRadio]
[_delegate myRadioCellDelegateDidCheckRadioButton:self];
}
}
Now just adapt your tableview controller with RadioCell (in .m file)
//MyTableViewController.m
#interface MyTableViewController () <RadioCellDelegate>
#end
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"RadioCell";
RadioCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[RadioCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel = #"Coke"; //or whatever you want
cell.delegate = self;
return cell;
}
-(void) myRadioCellDelegateDidCheckRadioButton:(RadioCell*)checkedCell {
NSIndexPath *checkPath = [self.tableView indexPathForCell:checkedCell];
for (int section = 0; section < [self.tableView numberOfSections]; section++) {
if(section == checkPath.section) {
for (int row = 0; row < [self.tableView numberOfRowsInSection:section]; row++) {
NSIndexPath* cellPath = [NSIndexPath indexPathForRow:row inSection:section];
RadioCell* cell = (CustomCell*)[tableView cellForRowAtIndexPath:cellPath];
if(checkPath.row != cellPath.row) {
[cell unCheckRadio];
}
}
}
}
}
Simple solution for a 2-option radio button UITableView (but you get the idea):
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSIndexPath *newIP;
if (!indexPath.row)
newIP = [NSIndexPath indexPathForRow:indexPath.row+1 inSection:0];
else
newIP = [NSIndexPath indexPathForRow:indexPath.row-1 inSection:0];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryCheckmark)
cell.accessoryType = UITableViewCellAccessoryNone;
else{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
UITableViewCell *newCell = [tableView cellForRowAtIndexPath:newIP];
newCell.accessoryType = UITableViewCellAccessoryNone;
}
}
One solution would be to make use of the table views native selection capabilities.
In a standard UITableView it's only possible to have one row selected at a time and you can use this to your advantage. By setting "Selection" in storyboard to "None" the selection of a row will not be visible.
Now you can implement your own selection display. You can override the method -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath to update your cell when it gets selected.
And you can override the method -(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath to change the cell when it's no longer selected.
UITableViewDelegate automatically calls didSelectRowAtIndexPath on the old selection, when a new selection is made, keeping the selection unique like radio buttons.
I put together a little sample project for you to try, you can download it here.
Hopefully, I have been at least a bit helpful.
Cheers!

Resources