Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UITableView titleForHeaderInSection shows all caps

I am using titleForHeaderInSection to show a header for a UITableView section. It worked fine with the iOS6 SDK, but the iOS7 SDK shows the header in all CAPS.

I guess it's part of Apple's updated Human Interface Guidelines; all examples in there show headers in all caps. Also, all section headers in Settings on my iPhone are in all caps.

However, I wonder if there is a way around that. Normally, I wouldn't mind showing caps if that improves consistency, but when I need to show people's names in a section header, it's a bit awkward.

Anybody any idea how to get around to capitalization?

like image 530
gbroekstg Avatar asked Sep 20 '13 09:09

gbroekstg


14 Answers

Yes, we had very much a similar problem to this, and my own solution was as follows:

The Apple UITableViewHeaderFooterView documentation (the link to it is irritatingly long but you can find it easily with your favourite search engine) says you can access the textLabel of the header view without having to format your own view via viewForHeaderInSection method.

textLabel A primary text label for the view. (read-only)

@property(nonatomic, readonly, retain) UILabel *textLabel Discussion Accessing the value in this property causes the view to create a default label for displaying a detail text string. If you are managing the content of the view yourself by adding subviews to the contentView property, you should not access this property.

The label is sized to fit the content view area in the best way possible based on the size of the string. Its size is also adjusted depending on whether there is a detail text label present.

With some additional searching the best place to modify the label text was the willDisplayHeaderView method (suggested in How to implement `viewForHeaderInSection` on iOS7 style?).

So, the solution I came up with is pretty simple and just does a transformation of the text label string, after it's actually been set by titleForHeaderInSection:

-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
        //I have a static list of section titles in SECTION_ARRAY for reference.
        //Obviously your own section title code handles things differently to me.
    return [SECTION_ARRAY objectAtIndex:section];
}

and then simply call the willDisplayHeaderView method to modify how it looks:

- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
{
    if([view isKindOfClass:[UITableViewHeaderFooterView class]]){
        UITableViewHeaderFooterView *tableViewHeaderFooterView = (UITableViewHeaderFooterView *) view;
        tableViewHeaderFooterView.textLabel.text = [tableViewHeaderFooterView.textLabel.text capitalizedString];
    }
}

You can put in your own 'if' or 'switch' clauses in there as the section number is also passed to the method, so hopefully it'll allow you to show your user/client name in capitalised words selectively.

like image 56
Animal451 Avatar answered Oct 04 '22 20:10

Animal451


solution which i found is add Title in "titleForHeaderInSection" method

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
   return @"Table Title";
}

and then call the willDisplayHeaderView method to Update :

- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section 
{
    UITableViewHeaderFooterView *header = (UITableViewHeaderFooterView *)view;
    header.textLabel.textColor = [UIColor darkGrayColor];
    header.textLabel.font = [UIFont boldSystemFontOfSize:18];
    CGRect headerFrame = header.frame;
    header.textLabel.frame = headerFrame;
    header.textLabel.text= @"Table Title";
    header.textLabel.textAlignment = NSTextAlignmentLeft;
}
like image 30
user3540599 Avatar answered Oct 04 '22 20:10

user3540599


If you want to just keep the string as it is, you could simply do this:

- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section {
    if ([view isKindOfClass:[UITableViewHeaderFooterView class]] && [self respondsToSelector:@selector(tableView:titleForHeaderInSection:)]) {
        UITableViewHeaderFooterView *headerView = (UITableViewHeaderFooterView *)view;
        headerView.textLabel.text = [self tableView:tableView titleForHeaderInSection:section];
    }
}

Swift solution:

func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
    if let headerView = view as? UITableViewHeaderFooterView, self.respondsToSelector(Selector("tableView:titleForHeaderInSection:")) {
        headerView.textLabel?.text = self.tableView(tableView, titleForHeaderInSection: section)
    }
}
like image 26
tobihagemann Avatar answered Oct 04 '22 22:10

tobihagemann


In Swift,

override func tableView(tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
    let headerView = view as! UITableViewHeaderFooterView
    headerView.textLabel.text = "My_String"
}
like image 41
Jeffrey Neo Avatar answered Oct 04 '22 21:10

Jeffrey Neo


One solution I found is to utilize UITableViewHeaderFooterView.

Instead of

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    return @"some title";
}

Do

- (UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    static NSString *identifier = @"defaultHeader";
    UITableViewHeaderFooterView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:identifier];
    if (!headerView) {
        headerView = [[UITableViewHeaderFooterView alloc] initWithReuseIdentifier:identifier];
    }
    headerView.textLabel.text = @"some title";
    return headerView;
}

The annoying downside is that the table view will no longer automatically adjust the section header height for you. So if your header heights varies, you'll have to do something like this:

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    id headerAppearance = [UILabel appearanceWhenContainedIn:[UITableViewHeaderFooterView class], nil];
    UIFont *font = [headerAppearance font];
    CGFloat viewWidth = CGRectGetWidth(tableView.frame);
    CGFloat xInset = 10;
    CGFloat yInset = 5;
    CGFloat labelWidth = viewWidth - xInset * 2;
    CGSize size = [sectionInfo.name sizeWithFont:font constrainedToSize:CGSizeMake(labelWidth, MAXFLOAT)];
    return size.height + yInset * 2;
}

I really don't like hard-coding layout information (the inset) this way, as it might break in the future version. If anyone has a better solution to get/set the header height, I'm all ears.

like image 34
Joseph Lin Avatar answered Oct 04 '22 22:10

Joseph Lin


Thanks @Animal451. This is more generic solution that would work with any type of header string.

// We need to return the actual text so the header height gets correctly calculated
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    return self.headerString;
}

- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
{
    UITableViewHeaderFooterView *header = (UITableViewHeaderFooterView *)view;
    [header.textLabel setText:self.headerString];       //String in the header becomes uppercase. Workaround to avoid that.

}

To avoid duplication the header string can be declared anywhere else. I have done it in the -viewDidLoad method.

like image 38
moon4e Avatar answered Oct 04 '22 20:10

moon4e


In addition to @Animal451's post. For swift 3 you can use

func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
  guard section == 0 ,
    let tableViewHeaderFooterView = view as? UITableViewHeaderFooterView
    else { return }

  tableViewHeaderFooterView.textLabel?.text = "Your awesome string"
 }

And then ignore - titleForHeaderInSection:

Keep in mind that this code is for 1st section only. If you want to go through all of your sections, you'll need to add support for them

like image 36
KIO Avatar answered Oct 04 '22 21:10

KIO


Simplest Solution for was below: Swift 2.x

func tableView(tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {

        header.textLabel?.text = header.textLabel?.text?.capitalizedString
}
like image 25
Dheeraj D Avatar answered Oct 04 '22 20:10

Dheeraj D


Swift 3.x:

if let headerView = view as? UITableViewHeaderFooterView {
    headerView.textLabel?.text? = headerView.textLabel?.text?.capitalized ?? ""
}
like image 29
Matt Bearson Avatar answered Oct 04 '22 21:10

Matt Bearson


Swift 5

Static TableViewController & storyboard section title. The below code will work the first letter capitalized.

override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
        let titleView = view as! UITableViewHeaderFooterView
        titleView.textLabel?.text =  titleView.textLabel?.text?.capitalized
    }
like image 22
Joyal Clifford Avatar answered Oct 04 '22 21:10

Joyal Clifford


The solution which worked for me was to create a simple UILabel Instance Variable to use as the section header view. (Your needs may be different, but for me, I only needed to have text in my header...) Then, inside viewForHeaderInSection, I set up the label as required, and return this label as the header view.

Then, whenever I want to update the text in the header, I simply change the label's text directly.

In the .h file:

@property (nonatomic, retain)  UILabel  *sectionHeaderLabel;

then in the .m file:

- (UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    return [self    refreshMySectionHeaderLabel]; // I created this handy little method to update the header text
}


// Get the latest text for the section header...
-(UILabel   *)  refreshMySectionHeaderLabel   {
    // Initialise the first time.    
    if( sectionHeaderLabel   ==  nil )   {
        sectionHeaderLabel   =   [[UILabel   alloc] initWithFrame:   CGRectNull];
    }

    // ...
    // May also set other attributes here (e.g. colour, font, etc...)
    // Figure out the text...    
    sectionHeaderLabel.text   =   @"Your updated text here...";


    return sectionHeaderLabel;
}

When I want to update my section header, I simply call:

[self refreshMySectionHeaderLabel];

...or you could simply call:

sectionHeaderLabel.text = @"The new text...";

Take note: I only have 1 section (section 0). You may need to account for multiple sections...

like image 23
Bob Cowe Avatar answered Oct 04 '22 22:10

Bob Cowe


One liner solution, based on @Dheeraj D answer:

override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
  (view as? UITableViewHeaderFooterView)?.textLabel?.text = (view as? UITableViewHeaderFooterView)?.textLabel?.text?.capitalized
}
like image 33
Federico Zanetello Avatar answered Oct 04 '22 20:10

Federico Zanetello


SWIFT

In implementation, i found out that you need to specify section header text in both titleForHeaderInSection & willDisplayHeaderView function, othervise header hides.

    extension ViewController: UITableViewDelegate, UITableViewDataSource {

        func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
            let sectionHeader =  datasource[section].sectionHeader  

            // Header Title
            return sectionHeader 
        }

        func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {

            guard let header = view as? UITableViewHeaderFooterView else { return }
            header.textLabel?.textColor = UIColor.darkGray
            header.textLabel?.font = UIFont.systemFont(ofSize: 20, weight: .semibold)
            header.textLabel?.frame = header.frame

            // Header Title
            header.textLabel?.text = datasource[section].sectionHeader
        }

    }
like image 43
nikdange_me Avatar answered Oct 04 '22 22:10

nikdange_me


Use the method viewForHeaderInSection to create the header title.

In viewDidLoad register a UITableViewHeaderFooterView

tableView.register(UITableViewHeaderFooterView.self, forHeaderFooterViewReuseIdentifier: "HeaderFooterViewID")

add delegate

    override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {

        let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: "HeaderFooterViewID")
        var config = header?.defaultContentConfiguration()
            
        let title = "My Header Title"
        let attribute = [ NSAttributedString.Key.foregroundColor: UIColor.blue ]
        
        config?.attributedText = NSAttributedString(string: title, attributes: attribute)
        
        header?.contentConfiguration = config
        
        return header
    }

You can adjust the attributed text more, reference

like image 33
Sreekuttan Avatar answered Oct 04 '22 22:10

Sreekuttan