change button state in cellForRowAtIndexPath - iphone

this is driving me MAD now.. I have a UItableview. Based on an NSMutableArray, I populate it.
I set up in reuseTableViewCellWithIdentifier with the following
cellRectangle = CGRectMake((ARROW_OFFSET + 5), (ROW_HEIGHT - LABEL_HEIGHT) / 2.0, ARROW_WIDTH, LABEL_HEIGHT);
UIButton *tmpButton = [[UIButton alloc] initWithFrame:cellRectangle];
[tmpButton initWithFrame:cellRectangle];
[tmpButton setImage:[UIImage imageNamed:#"icon_edit.png"] forState:UIControlStateNormal];
[tmpButton setImage:[UIImage imageNamed:#"icon_no.png"] forState:UIControlStateDisabled];
[tmpButton addTarget:self action:#selector(editSelectedRow:) forControlEvents:UIControlEventTouchUpInside];
tmpButton.tag = ARROW_TAG;
[cell.contentView addSubview: tmpButton];
[tmpButton release];
then in cellForRowAtIndexPath I have the following lines of code
UIButton *button = (UIButton *)[cell viewWithTag:ARROW_TAG];
[button setTag:indexPath.row];
if (counterHasStarted == 1) {
NSLog(#"yes");
button.enabled = NO;
} else {
button.enabled = YES;
}
the button shows nicely, but for some reason when the counterHasStarted variable (which is an int is set, it doesn't change! I can change UILabels based on the above code (checking if counterHasChanged is 1 or 0).
Any ideas what's going on??

-cellForRowAtIndexPath: will only get called when the table view needs a new UITableViewCell because the user scrolled.
I guess you're changing counterHasStarted and expect the button enabled state to change? You could reload the data when you change counterHasStarted ([yourTableView reloadData]). Then the table view will call -cellForRowAtIndexPath: for all the cells that are currently visible, and you can enable or disable the buttons as needed.

Related

Hiding button on tableview on a particular cell

I have created table. On each cell I am adding button depending upon the value from flag array.
Here is my code for adding button on cell
if ([[self.flags objectAtIndex:indexPath.row]
isEqualToString:#"false"])
{
UIButton *btnFlag = [UIButton buttonWithType:UIButtonTypeCustom];
[btnFlag addTarget:self
action:#selector(flagButtonPressed:)
forControlEvents:UIControlEventTouchDown];
btnFlag.backgroundColor = [UIColor redColor];
[btnFlag setTitle:#"flag" forState:UIControlStateNormal];
btnFlag.frame = CGRectMake(230, 40, 50, 20);
[cell addSubview:btnFlag];
}else if ([[self.flags objectAtIndex:indexPath.row] isEqualToString:#"true"])
{
UIButton *btnFlag = [UIButton buttonWithType:UIButtonTypeCustom];
[btnFlag setHidden:YES];
[cell addSubview:btnFlag];
}
-(void)flagButtonPressed:(id)sender {
UITableViewCell *owningCell = (UITableViewCell*)[sender superview];
indexPathToCell = [self.cotDetailsTbl indexPathForCell:owningCell];
// some stuff }
In the above method Im calling the api and depending upon the response obtained Im replacing the value in flag array from false to true. Once the value in flag array becomes true Im reloading table.
But the problem is when Im reloading table the button still appears its not hidden
Thanks
In your else part you again creating a new instance of button using UIButton *btnFlag = [UIButton buttonWithType:UIButtonTypeCustom] instead you need the existing UIbutton instance and set it to hidden.
Try using the following:
In if statement, assign a tag to each button
btnFlag.tag = indexPath.row
Now. in else do the following find the button by its tag and set hidden :
else if ([[self.flags objectAtIndex:indexPath.row] isEqualToString:#"true"])
{
UIButton *btnFlag = [cell.contentView viewWithTag:indexPath.row];
[btnFlag setHidden:YES];
}

How to save a reference to a control added programmatically?

I added 3 buttons programmatically to my view, then I added the buttons to an array so that I can access them at a later time:
for (i = 0; i < 3; i++)
{
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[view addSubview:button];
[_buttons addObject:button];
}
If I reference the button in my array and change the image of the button, it does not change the button on screen.
UIButton* button = [_buttons objectAtIndex: 0];
[button setImage:thumb forState:UIControlStateNormal];
I've found a way to change the image of the button by looping through all the subviews in my view, but is there a better way?
for (UIView* subView in ((UIView*)[self.view.subviews objectAtIndex:0]).subviews){
if ([subView isKindOfClass:[UIButton class]]){
UIButton *button = (UIButton*)subView;
if (button.tag == self.selected){
[button setImage:thumb forState:UIControlStateNormal];
}
}
}
A common reason for this is that your array has not been initialized. When this happens, Objective C does not complain or throw excetions: instead, it behaves as if the calls to add elements never happened. It also returns nil when you try getting items back.
Add this line to your viewDidLoad method:
_buttons = [NSMutableArray array];
This should solve the problem.
Possible this could help on a click event:
-(void)clickEvent:(id)sender
{
[sender setImage:thumb forState:UIControlStateNormal];
}
If this is how you are picking up the event.
When you do addSubview, view retains subview you are adding. Also addObject retains it. Hence both are different ojbects. Changing properties of object in array will not affect object retained by view.
You can avoid loop by using tags. While adding buttons on view set unique tags to them. And when you want to access them, get it using tag directly.
//set tags for buttons
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setTag:999];
[view addSubview:button];
//access using tag
UIButton *button = (UIButton*)[view viewWithTag:999];
[button setImage:thumb forState:UIControlStateNormal];
Add a tag to the button after creating it. And later use that tag to get that button.
for (i = 0; i < 3; i++)
{
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.tag = i+1;
[view addSubview:button];
[_buttons addObject:button];
}
Then you can access it like:
UIButton *button1 = (UIButton *)[self.view viewWithTag:1];
UIButton *button2 = (UIButton *)[self.view viewWithTag:2];
UIButton *button3 = (UIButton *)[self.view viewWithTag:3];
While adding UIControl programatically to use reference later add tag to it which should be different like:
yourBtn.tag = 111;
Now get reference of UIButton like this:
UIButton *button = (UIButton*)[yourViewWhereYouAdded viewWithTag:111];

How to maintain the state of a particular button in a UITableView (i.e. stop overwriting an image)

I have an iPhone app problem that's been bugging me for a few days and it really doesn't seem like it should be this difficult so I'm sure I'm missing something obvious. I have researched plenty of forum discussions on "similar" topics but nothing that actually addresses this issue, specifically.
To be clear, if there is some piece of documentation or some other source that I should research, please point me in the right direction.
Here goes...
I have a list of items that I display to the user within a table (uitableview). The cell (uitableviewcell) for each item is custom and contains two image buttons(uibuttons: green and red). As expected, for each item in the the table, the user can click any of the buttons. Based on a parameter called monitoringRequestType for a button, the button calls a separate process to update the server. If the state is "Approved",the image changes to 'alreadyapproved' and 'reject' respectively. So when I click on the red button, server updates the state to "Rejected" and image then changes to 'approve' and 'alreadyrejected'.
Simple, right?
So, here is the issue:
On clicking the reject button, the 'approve' image comes on top of the 'alreadyapproved' image (so both images can be seen) while 'alreadyrejected' image works fine.For brevity, I am only including the relevant code here (hopefully formatted properly):
CellForRow:
if(indexPath.section==0){
NSDictionary *dict=[saveJson objectAtIndex:indexPath.row];
NSString* sMonitoringType = [dict valueForKey:#"monitoringType"];
UIButton *button1= [[UIButton alloc] initWithFrame:CGRectMake(230,10,40,40)];
UIButton *button2= [[UIButton alloc] initWithFrame:CGRectMake(280,10,40,40)];
if([sMonitoringType compare:#"Pending"] == NSOrderedSame){
[button1 setImage:[UIImage imageNamed:#"approve"]
forState:UIControlStateNormal];
[button1 addTarget:self
action:#selector(greenButtonPressed:withEvent:)
forControlEvents:UIControlEventTouchUpInside];
button1.tag= indexPath.row;
[button2 setImage:[UIImage imageNamed:#"reject"]
forState:UIControlStateNormal];
[button2 addTarget:self
action:#selector(redButtonPressed:withEvent:)
forControlEvents:UIControlEventTouchUpInside];
button2.tag= indexPath.row;
} else if([sMonitoringType compare:#"Approved"] == NSOrderedSame){
[button1 setImage:[UIImage imageNamed:#"alreadyapproved"]
forState:UIControlStateNormal];
[button2 setImage:[UIImage imageNamed:#"reject"]
forState:UIControlStateNormal];
[button2 addTarget:self
action:#selector(redButtonPressed:withEvent:)
forControlEvents:UIControlEventTouchUpInside];
button2.tag= indexPath.row;
} else if([sMonitoringType compare:#"Rejected"] == NSOrderedSame){
[button1 setImage:[UIImage imageNamed:#"approve"]
forState:UIControlStateNormal];
[button2 setImage:[UIImage imageNamed:#"alreadyrejected"]
forState:UIControlStateNormal];
[button1 addTarget:self
action:#selector(greenButtonPressed:withEvent:)
forControlEvents:UIControlEventTouchUpInside];
button1.tag= indexPath.row;
}
[cell addSubview:button1];
[cell addSubview:button2];
[button1 release];
[button2 release];
}
return cell;
}
The UIButtons are being added to the cell's subview whenever the cell reloads (you're reusing cells, right?). You should reuse the older buttons already added to the cell's subview instead of adding new ones and just to verify the issue, stop reusing the cells (memory inefficient, should not be done in production code!). To reuse the older buttons, set a unique tag for each button and get them back as [cell viewWithTag:uniqueTag]
if(indexPath.section==0){
NSDictionary *dict=[saveJson objectAtIndex:indexPath.row];
NSString* sMonitoringType = [dict valueForKey:#"monitoringType"];
UIButton *button1= [cell viewWithTag:900];
UIButton *button2= [cell viewWithTag:901];
if(!button1){// button1 doesn't exist yet (first time)
button1 = [[UIButton alloc] initWithFrame:CGRectMake(230,10,40,40)];
[cell addSubview:button1];
}
if(!button2){// button2 doesn't exist yet (first time)
button1 = [[UIButton alloc] initWithFrame:CGRectMake(280,10,40,40)];
[cell addSubview:button2];
}
......

Putting a button in table footer view

I am creating a custom button and putting it in my table's footer view but the button is going way out from the right corner.
What is wrong here!?!
Here is my code and output image:
UIButton *aButton = [UIButton buttonWithType:UIButtonTypeCustom];
[aButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[aButton setTitleColor:[UIColor colorWithWhite:0.0 alpha:0.56] forState:UIControlStateDisabled];
[aButton setBackgroundImage:[[UIImage imageNamed:#"test.png"] stretchableImageWithLeftCapWidth:kButtonSliceWidth topCapHeight:0] forState:UIControlStateNormal];
[aButton setTitle:#"Click me" forState:UIControlStateNormal];
[aButton.titleLabel setFont:[UIFont boldSystemFontOfSize:kFontSize14]];
[aButton setFrame:CGRectMake(10.0, 15.0, 300.0, 44.0)];
[self.tableView setTableFooterView:aButton];
I added the button in the UIView and then set the tableFooterView to this UIView object and it worked. We cannot directly put UIButton as tableFooterView.
Try doing like this. Set IBOutlet UIView *footerView; and synthesize it. Add it as a subview using the method-
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
if(footerView == nil) {
//allocate the view if it doesn't exist yet
footerView = [[UIView alloc] init];
//create the button
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button setFrame:CGRectMake(10, 3, 300, 44)];
//set title, font size and font color
[button setTitle:#"Click Me" forState:UIControlStateNormal];
[button.titleLabel setFont:[UIFont boldSystemFontOfSize:18]];
//set action of the button
[button addTarget:self action:#selector(clickPressed:)
forControlEvents:UIControlEventTouchUpInside];
//add the button to the view
[footerView addSubview:button];
}
//return the view for the footer
return footerView;
}
One important addition to Legolas' fine answer: You'll need to implement the tableView delegate method:
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
foot 50;
}
This was driving me nuts because the button (or, in my case, buttons) were not responding to the touch event. Adding the delegate method made it all better. :-)

UIButton to cover a UITableViewCell

I'd like one of my table rows to be a button that takes up an entire row of my UITableView. I figured the best way to go about this is to instantiate a UIButton, and give it the same frame size as an instance of UITableViewCell, and add that as a subview to the cell. I'm almost there, but quite a few pixels off to not get that perfect touch to it. Is there a better approach to this, or perhapsps can my placement accuracy be fixed up to get that perfect alignment?
cell = [tv dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil) {
cell = [self tableviewCellWithReuseIdentifier:CellIdentifier];
}
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button setFrame:CGRectMake(0.0f, 5.0f, 320.0f, 44.0f)];
[button setTitle:#"Do Stuff" forState:UIControlStateNormal];
[button addTarget:self action:#selector(doStuff:) forControlEvents:UIControlEventTouchUpInside];
[cell addSubview:button];
You can fake it in your didSelectRowAtIndexPath: method.
Have the tableView cell act as the button.
[[[self tableView] cellForRowAtIndexPath:indexPath] setSelected:YES animated:YES];
[self doStuff];
[[[self tableView] cellForRowAtIndexPath:indexPath] setSelected:NO animated:YES];
Use setSelected: animated: to fake a button press and have it fade.
Might do the trick for you.
Class(UITableViewCell) has contentView property.
So I put basic button in contentView of UITableViewCell variable.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
・・・
UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
btn.frame = CGRectMake(230.0f, 4.0f, 60.0f, 36.0f);
[btn setTitle:#"OK" forState:UIControlStateNormal];
[btn setTitle:#"OK" forState:UIControlStateSelected];
[btn addTarget:self action:#selector(onClickRename:) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:btn];
・・・
return cell;
}
Sorry, poor my English.
if you want it to fit perfectly, just call the cell's bounds as your CGRect. do it like this:
button.frame = cell.bounds;
That should get your button to be exactly the same as your cell. Hope that helps!
Cord
This may be beside the point, but your code may have the problem where another button is added to the cell every time the cell is re-used.
I had the same problem as you. And Ryan gave you the answer: use the cell itself as a button with the didSelectedRowAtIndexPath: method.
You can also add add a UIImage to your UITableViewCell to make the cell appear to be a button.
You can also create a view with a button and place it in the footer of the section above it. That way you don't need to worry about the cell image in the background. I've done this to place two half-width buttons side-by-side in a grouped table view.
FWIW, I put the button in my app at CGRectMake(9, 0, 302, 45)
and I think it looks perfect.
UIButton *btnView = [[UIButton alloc] init];
btnView.frame = CGRectMake(52.0f, 2.0f, 215.0f, 38.0f);
[btnView setImage:[UIImage imageNamed:#"invite.png"] forState:UIControlStateNormal];
[btnView addTarget:self action:#selector(showInviteByMail) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:btnView];
[btnView release];