UITableview titleForHeaderInSection not displaying correctly - iphone

I have some VERY simple code to return the title for a section header:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
if (section==0) {
return #"";
} else if (section==1) {
return #"Actions";
} else if (section==2) {
return #"Attached To";
}
return #"";
}
For some reason when the headers are actually displayed on the simulator, half of the time they're simply the first letter and then ellipses. Scrolling up and down (to refresh the header view most likely) will result in the title showing correctly roughly half the time and showing incorrectly the other half of the time.
Do anyone have any idea what could be causing this? I think this is more of a recent development, but it seems to happen in almost all UITableViews in my application. I don't want to say this is a 3.2 issue, but it might have started happening around then, but either way it must be related to the code somehow. Thank you.

I've figure it out: the actual problem with the code was returning #"". If you return just a blank string, instead of nil, it will cause a problem with the display of headers and footers.
You need to instead return a nil string to get all headers and footers to display correctly. Returning a space #" " will still leave the vertical space for the header so that is not a viable option. I've changed all instances of return #""; to simply return nil;

i copy&pased your code to one of my projects and it works flawless. (sdk 3.2.1)
Maybe the error is in another part?
Are creating your own tablecells? If so, are you returning the apropiate height from "tableView:heightForRowAtIndexPath:"?
(that problem did hit me once)

When setting the Section Header Titles, I have better success in using an empty NSString that gets set to the corresponding Section, and then later release that string when completed; as well as limiting my use the nested If()Else() statments.
I try to keep it simple and clean. Of course for those tables where I have more than 3 sections, I use a "Switch" statement in place of the If() statements.
The great thing about this function is that it gets called as many times-(number of sections) that you have and will run through the code each time. The NSString *sectionHeader=nil; gives the compiler a value to be returned, regardless of what is embedded within your If() statements. Otherwise, you get warnings because the compiler doesn't search within the If() statements for your return value.
You can also initialize the String to a "Default" value, e.g. NSString *sectionHeader = #"Default Header Title";. If non of the If() statements are satisfied, then the allocated default header value will remain the same throughout the function and thus get returned as sectionHeader for the Title.
Basic Structure Below:
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
//TEMP SECTION STRING HOLDER:
NSString *sectionHeader = nil;
//SET TITLE FOR EACH SECTION:
if(section == 0) {
sectionHeader = #"Section Header No. 1";
}
if(section == 1) {
sectionHeader = #"Section Header No. 2";
}
if(section == 2) {
sectionHeader = #"Section Header No. 3";
}
//RETURN THE SECTION HEADER FOR EACH SECTION:
return sectionHeader;
}

Related

How to move labels in ios

Here i need to hide the phone number, email , birthDate, anniversary date and other labels in case there is no values for those fields. How can i do this?
Many ways, starting with the simplest:
self.emailLabel.hidden = YES;
But you probably want to reformat the other parts of the view to fit the empty space. Keeping it simple, you would then do something like this:
self.phoneLabel.frame = CGRectOffset(self.phoneLabel.frame, 0, -self.emailLabel.bounds.size.height);
... and so on for anything below. But you can see how this would become tedious. The next and probably best alternative is a UITableView that adjusts it's section count based on whether some of that data is present. That would go like this. Prepare a mutable array of arrays with the parts of your model and their values.
- (void)prepareModel {
self.model = [NSMutableArray array];
[self.model addObject:#[#"Name", #"Judy"]; // get "Judy" from your data
if (/* model has email */) {
[self.model addObject:#[#"Email", #"judy#gmail.com"]; // get email from your model
}
// and so on for conditional parts of your model
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return self.model.count;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
return self.model[section][0];
}
And the cellForRow would init the cell using self.model[section][1].
What you can do is simply hide the UILabel's if the value for the NSStrings that you are putting them in is NULL/nil .
NSString *labelString;
if([labelString length]>0)
{
}
else
Label.hidden = YES;
It is probably a better idea to use a UITableView to do this, by putting the labels in rows of the tables. If the labels are empty, you can delete the table rows and iOS will dynamically resize the table height for you.

Accessing "default" methods of UITableView

I try to set up a tableView. I use standard cells for all sections' rows except in the last section (containing one row). Thus, I would also like to use the standard layout for all those sections except that special one.
A short example is the following, my "special" cell is in section 3 (there is only one row):
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
if (section == 3)
return 5;
return **????**;
}
At ??? I would like to return the width calculated from UITableView (just as if I did not implement the method).
[super self:tableView
heightForHeaderInSection:(NSInteger)section];
does not work. I know I can access
[tableView setionHeaderHeight]
which is by default 10 and obviously does not take into account that I have section headings for the other sections, which will require additional space. I tried that, but it will then get the sections too close (see screenshot):
(Note: the section I am interested in is the one which does not look like a cell: the one with the dates (invisible background)).
So, the easiest thing would be to hand over the layout to the standard implementation which is perfect - except for section3.
What are my options?
Just in case: there is a new constant introduced in iOS 5, called UITableViewAutomaticDimension. As the documentation says, you should return it from your delegate method when you want UITableView to use a default value.
So, the code for your case would be:
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
if (section == 3) {
return 5;
} else {
return UITableViewAutomaticDimension;
}
}
You seem a bit confused about heightForHeaderInSection - it returns the height of a table section header (this is the "title" of a table section), not a row. iOS calls this method to ask for the height of just a single section header, irrespective of any other section headers there might be.
If you want to use the default, just return [tableView sectionHeaderHeight] for any section other than 3 - you don't need to "take into account that [you] have other section headers", as it's asking for the height of the header for section alone. It will ask again for the heights of others (and compute the relative positions with of rows and other sections automatically).
You do not have a super implementation tableView:heightForHeaderInSection: since you are not subclassing any abstract base implementation for UITableViewDelegate. The table view is instead decided if the default height should be used by inspecting your delegate implementation to see if the method is available.
It is a quite a huge concept to wrap your head around, especially if coming from Java or C#. Methods in Objective-C protocols can be optional, and their absence means use default.
Your method should probably be implemented as:
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
if (section == 3) {
return 5;
} else {
return 36;
}
}
The default height for grouped and plain tableviews are different (22points for plain). The default values are not exposed by UITableView, not even as private methods. File bug at http://bugreport.apple.com to make this a public constant.
After overriding heightForHeaderInSection and doing a side-by-side comparison, the height for the header in the first row is larger than the rest. This isn't pixel perfect, but it's very close:
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
if (section == 0 ) {
return 46.0;
} else if (section == myCustomRow) {
return 12345.0; // custom height
} else {
return 36.0;
}
}

Change the number of rows in a section depending on a variable

In my 'Sectioned' UITableView I have two sections, the first one for Attributes like name and the second one is editable where you can add objects.
Here's a picture of it:
alt text http://fwdr.org/bm9w
There's an attribute that the user can change (in this case Type) which would to change the number of rows in second section. To be more specific, if one property is selected the maximum number of rows is 2 and then there would be no Add New… row.
Here's what I've tried (in my UITableViewController) …
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if ([self isToManyRelationshipSection:section]) {
NSArray *sectionKeys = [rowKeys objectAtIndex:section];
NSString *row0Key = [sectionKeys objectAtIndex:0];
if ([[NSString stringWithFormat:#"%#", [managedObject valueForKey:#"type"]]
isEqualToString:[NSString stringWithFormat:#"One on One"]] && [[managedObject valueForKey:row0Key] count] == 2){
return [[managedObject valueForKey:row0Key] count];
}
return [[managedObject valueForKey:row0Key] count] +1;
}
return [rowLabels countOfNestedArray:section];
}
But if the user tries to remove a row when there are already 2 rows the app crashes because there would be the same number of rows before and after the deletion.
How do I get around this and do this properly?
First off, the numberOfRows.. method wouldn't appear to me as the proper place to do this kind of logic. I'd rather create a seperate method to determine and return the current game mode (and keep the gamemode updated whenever the user selects another mode). I'd associate integers with gamemodes (1 = "one on one", 2 = "all against all"...), that way in the numberOfRows Method you just need to check "is the current section == 1?" && "which game mode are we in?" to determine how many rows are needed.
If you keep track of the gamemode properly, you don't need to check for equal strings anymore, too.
I ended up doing this differently to what I first wanted to do.
My reasoning was that my current implementation gave me an error in the debugger which in turn crashed the app. This error seemed un-avoidable so I decided to simply disable the cell if there are two rows, instead of hiding it.
To do this in my tableView:cellForRowAtIndexPath: method I added the following code (in my if statement) to make it look un-selectable to the user:
cell.textLabel.textColor = [UIColor lightGrayColor];
cell.editingAccessoryType = UITableViewCellAccessoryNone;
And in the tableView:didSelectRowAtIndexPath: method I left my if statement blank so it wouldn't push another view controller or add a object. Although I did include this code to deselect the row:
[self.tableView deselectRowAtIndexPath:indexPath animated:NO];

Why am I getting two section headers on this grouped table?

I'm sure this is some easy-to-fix issue that I've missed, but I can't figure it out. I've got a grouped table view with 3 sections. I'm using the following code to generate section headers:
-(NSString*)tableView:(UITableView*)tableView titleForHeaderInSection:(NSInteger)section {
if (section == 0) {
NSString *header = #"Header 1";
return header;
}
if (section == 1) {
NSString *header = #"Header 2";
return header;
}
else {
NSString *header = #"Header 3";
return header;
}
}
When my table is displayed, there are two headers for each section - one with white text on a gray bar that stretches across the screen (like the letter separators in the Contacts app), and one in gray text on the table background (which is the one I want). Both headers have identical text. Where is the first header coming from?
The code you have presented looks completely normal (though it probably is generating a warning for not having a return null; at the end. The issue is somewhere else, but there's no way to determine what that is with what you've given.

Custom UITableView section header views are breaking

I have a custom UIView subclass that i'm trying to use as a header for one of my grouped tableview sections. I save an instance of that view in the tableViewController and use that to return the height for the header section as well as the view itself. the problem is that somehow that instance variable changes from a UIView to a CALayer in the middle of a reloadData call which causes a crash, since the instance has a special method to return it's expected height. this is the code that crashes:
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
if (section == 0)
{
return [self.dataHeader frameHeight];
}
return 0.0f;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
if (section == 0)
{
return self.dataHeader;
}
return nil;
}
I set a breakpoint at the first return in the if block of the heightForHeaderInSection method, and it hits it 4 times; the first three return the dataHeader successfully, while the fourth time shows it to be a CALayer and crashes with a doesNotRecognizeSelector exception (my tableview has 2 sections if that makes a difference). Is there any reason why this happens, and is there a way to stop it?
What does your initialization code for dataHeader look like? When you initialize dataHeader, are you properly retaining it?
My guess is that your dataHeader view is getting released before you intended.
The problem seems to be that you have 2 sections and somehow the app thinks there are 4. Here's how I would debug this problem:
1) What is numberOfSectionsInTableView returning (is it implemented)?
I assume that each header method should be called n times, where n is the number of sections in your table. I would also assume that the app asks the aforementioned delegate what n is.
2) What are the values of section each time these delegates are called?
There should only be one call per section, unless I'm missing something, and I would be amazed if the delegate gets called more than once with the same section value.