I have a table with customized headers for the sections. In addition to that, I implemented a collapsing feature, so that when a header is touched, all non-adressed sections are reduced, and the adressed section is expanded.
I realized that by using UIButtons as background views. Furthermore, the buttons have different colors and text, depending on their state (expanded vs not expanded).
I have a problem, similar to that reusidentifier problem, i.e. if u dont reuse cells already allocated in a table, certain fragments appear, if u start to scroll. Here it only happens to my first section, nevertheless it appears fragmented and duplicated....
Is there anything similar to reusing headerviews already allocated once like the method reusIdentifier for UITableViewCells?
Or is there a better approach?
Allocating the Buttons in advance to store them in array didnt do the trick for me...
Here's some code:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, self.tableView.frame.size.width, 40)];
[button setShowsTouchWhenHighlighted:NO];
[button setTitleShadowColor:[UIColor clearColor] forState:UIControlStateNormal];
[button addTarget:self action:#selector(collapse:) forControlEvents:UIControlEventTouchUpInside];
button.tag = section;
[button setAdjustsImageWhenHighlighted:NO];
button.backgroundColor = [UIColor colorWithRed:63.0f/255.0f green:154/255.0f blue:201/255.0f alpha:1.0f];
[button.titleLabel setFont:[UIFont fontWithName:#"Helvetica" size:14.0]];
[button setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft];
[button setContentVerticalAlignment:UIControlContentVerticalAlignmentCenter];
if (section == 0) {
// [button setBackgroundImage:[UIImage imageNamed:#""] forState:UIControlStateNormal];
[button setTitle:#" Newsroom" forState:UIControlStateNormal];
} else {
[button setTitle:[NSString stringWithFormat:#" Sektion %d", section] forState:UIControlStateNormal];
}
if (section == mySection) {
[button setBackgroundImage:[UIImage imageNamed:#"sectionHeader_active.png"] forState:UIControlStateNormal];
[button setBackgroundImage:[UIImage imageNamed:#"sectionHeader_active.png"] forState:UIControlEventTouchUpInside];
[button.titleLabel setTextColor:[UIColor whiteColor]];
} else {
[button setBackgroundImage:[UIImage imageNamed:#"sectionHeader_inactive.png"] forState:UIControlStateNormal];
[button setBackgroundImage:[UIImage imageNamed:#"sectionHeader_inactive.png"] forState:UIControlEventTouchUpInside];
[button.titleLabel setTextColor:[UIColor colorWithRed:96.0f/255.0f green:96/255.0f blue:97/255.0f alpha:1.0f]];
}
return [button autorelease];
}
I also implemented a collapsing section table using UIButton header views. What I found was that it was folly trying to cache and resuse the views, because you don't know when the UITableView is done with them (I got crashes).
I recommend implementing your state change by: updating your data model; performing all the row insert/deletes to perform the collapses/expand; then doing a [tableView reloadData], which will call viewForHeaderInSection, where you use the state of your data model to return the appropriately formatted uibutton view.
Related
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];
}
......
I want to add a button in a UITableViewCell. This is my code: `
if (indexPath.row==2) {
UIButton *scanQRCodeButton = [[UIButton alloc]init];
scanQRCodeButton.frame = CGRectMake(0.0f, 5.0f, 320.0f, 44.0f);
scanQRCodeButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
scanQRCodeButton.backgroundColor = [UIColor redColor];
[scanQRCodeButton setTitle:#"Hello" forState:UIControlStateNormal];
[cell addSubview:scanQRCodeButton];
}`
Now, when I run the app, I see only a blank row ! Any ideas ?
While it's natural to put it in the contentView of the cell, I'm fairly certain that is not the problem (actually, in the past, I've never had subviews displayed correctly in the contentView, so I've always used the cell).
Anyway, the problem involves the first three lines of when you start creating your button. The first two lines are fine, but the code stops working with:
scanQRCodeButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
buttonWithType: is actually a convenience method to create a button (it's like a compact alloc-init). Therefore, it actually "nullifies" your past two lines (you basically created the button twice). You can only use either init or buttonWithType: for the same button, but not both.
UIButton *scanQRCodeButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
scanQRCodeButton.frame = CGRectMake(0.0f, 5.0f, 320.0f, 44.0f);
scanQRCodeButton.backgroundColor = [UIColor redColor];
[scanQRCodeButton setTitle:#"Hello" forState:UIControlStateNormal];
[cell addSubview:scanQRCodeButton];
This will work (note that you can use cell.contentView if you wanted). In case you're not using Automatic Reference Counting (ARC), I would like to mention that you don't have to do anything in term of memory management, because buttonWithType: returns an autoreleased button.
UIButton *deletebtn=[[UIButton alloc]init];
deletebtn.frame=CGRectMake(50, 10, 20, 20);
deletebtn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[deletebtn setImage:[UIImage imageNamed:#"log_delete_touch.png"] forState:UIControlStateNormal];
[deletebtn addTarget:self action:#selector(DeleteRow:) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:deletebtn];
or
// Download class and import in your project UIButton+EventBlocks
UIButton *deletebtn=[UIButton buttonWithType:UIButtonTypeRoundedRect];
[deletebtn setFrame:CGRectMake(170,5, 25, 25)];
deletebtn.tag=indexPath.row;
[deletebtn setImage:[UIImage imageNamed:#"log_delete_touch.png"] forState:UIControlStateNormal];
[deletebtn setOnTouchUpInside:^(id sender, UIEvent *event) {
//Your action here
}];
[cell addSubview:deletebtn];
You want to add any custom UI elements to the cell's contentView.
So, instead of [cell addSubview:scanQRCodeButton];
do [cell.contentView addSubview:scanQRCodeButton];
Try adding [cell.contentView addSubview:scanQRCodeButton]; or if you want the button to the left side look at my question at the answer, to move the textLabel to the side. If you want the button to the right then just set it as your accesoryView like this cell.accesoryView = scanQRCodeButton;.
Method setTitle does not work in my code, so I have set by using
[UIButton.titleLabel setText:#""]
instead of using setTitle method.
Please try again with following code:
[scanQRCodeButton.titleLabel setText:#"Hello"];
Then it would work well.
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. :-)
I have a UITableView with three section. I have a custom UITableViewCell. I want to put a button in the first section of my table view to handle an action.
How to can do this please?
just create the button programmatically
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button addTarget:self
action:#selector(aMethod:)
forControlEvents:UIControlEventTouchDown];
[button setTitle:#"Show View" forState:UIControlStateNormal];
button.frame = CGRectMake(80.0, 210.0, 160.0, 40.0);
[view addSubview:button];
You can also put the button directly into a UITableViewCell which is located in your first section. In your cellForRowAtIndexPath you can use for example:
UIButton *yourButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[yourButton setTitle:#"Click me" forState:UIControlStateNormal];
[yourButton setFrame: CGRectMake( 20.0f, 3.0f, 280.0f, 33.0f)];
[yourButton addTarget:self action:#selector(clickAction) forControlEvents:UIControlEventTouchUpInside];
[cell addSubview:yourButton];
This example will look like this:
and will be places directly in the cell.
If you want to put it in the section header (rather than a cell), you could:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
if(section==0)
{
// create button and return it
}
}
I've got a UIButton on a table cell that is meant to pop up a UIActionSheet but the problem is the didSelectRowAtIndexPath captures that touch and its action takes precedence. Any clever way to override that action when the user touches the button and still have the default action when the user presses elsewhere in the cell?
Too bad there is no MoveToFront property.
How you have add button on cell
i am putting one sample
in
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
...
UIButton *btnDetail = [UIButton buttonWithType:UIButtonTypeRoundedRect] ;
[btnDetail setFrame:CGRectMake(225.0f, 15.0f, 65.0f, 20.0f)] ;
//btnDetail.backgroundColor = [UIColor grayColor];
[btnDetail setTitle:#"Detail" forState:UIControlStateNormal];
[btnDetail setTitleColor: [UIColor redColor] forState: UIControlStateNormal];
[btnDetail.titleLabel setFont:[UIFont fontWithName:#"Verdana-Bold" size:12]];
[btnDetail setBackgroundColor:[UIColor clearColor]];
[btnDetail sizeThatFits:btnDetail.frame.size];
[cell addSubview:btnDetail];
[btnDetail addTarget:self
action:#selector(function1:)
forControlEvents:UIControlEventTouchUpInside];
[btnDetail setImage:[UIImage imageNamed:#"btn-detail.png"] forState:UIControlStateNormal];
if you have written
[btnDetail addTarget:self
action:#selector(function1:)
forControlEvents:UIControlEventTouchUpInside];
your button should able to capture touch event and function1 should be called... on it's touch event...