Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS NSAttributedString on UIButton

I'm using iOS 6, so attributed strings should be easy to use, right? Well... not so much.

What I want to do:

Using a custom subclass of UIButton (it doesn't do anything custom to titleLabel), I'd like to have a multi-line, attributed title that is:

  1. All caps (I realize that's not part of the attributes) on the first line
  2. Bolded on the first line
  3. Underlined on the first line
  4. "Normal" weight on the second line
  5. Non-underlined on the second line
  6. Centered on both lines

I've been able to get #'s 1 through 5 so far (at least, I thought I did, but current testing is yielding errors with multi-line text), but when I tried to do something (anything!) to get the text to be centered, my app keeps crashing. When I try to get all 6 items working (through various methods), I get the following crash/error:

Terminating app due to uncaught exception  'NSInternalInconsistencyException', reason:  'NSAttributedString invalid for autoresizing,  it must have a single spanning paragraph style (or none) with a non-wrapping lineBreakMode.' 

Based on what I've tried, it appears that I can have one of the following options, but not both:

  1. A multi-line, centered label
  2. An attributed label

I can live with one or the other if I must, but I can't believe that I can't have what seems to be a fairly straightforward concept.

Can someone please tell me what I've got wrong?

Here's the last iteration of the code I'm trying:

NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; [style setAlignment:NSTextAlignmentCenter]; [style setLineBreakMode:NSLineBreakByWordWrapping];  UIFont *font1 = [UIFont fontWithName:@"HelveticaNeue-Medium" size:20.0f]; UIFont *font2 = [UIFont fontWithName:@"HelveticaNeue-Light"  size:20.0f]; NSDictionary *dict1 = @{NSUnderlineStyleAttributeName:@(NSUnderlineStyleSingle),                           NSFontAttributeName:font1}; NSDictionary *dict2 = @{NSUnderlineStyleAttributeName:@(NSUnderlineStyleNone),                             NSFontAttributeName:font2};  NSMutableAttributedString *attString = [[NSMutableAttributedString alloc] init]; [attString appendAttributedString:[[NSAttributedString alloc] initWithString:@"LINE 1\n"    attributes:dict1]]; [attString appendAttributedString:[[NSAttributedString alloc] initWithString:@"line 2"      attributes:dict2]]; [[self buttonToStyle] setAttributedTitle:attString forState:UIControlStateNormal]; [[[self buttonToStyle] titleLabel] setNumberOfLines:0]; [[[self buttonToStyle] titleLabel] setLineBreakMode:NSLineBreakByWordWrapping]; 
like image 225
mbm29414 Avatar asked Jul 19 '13 21:07

mbm29414


1 Answers

It looks to me like you forgot in your code to use the "style" object that you set up.. you just instantiated it. You should modify your code to look like this:

NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; [style setAlignment:NSTextAlignmentCenter]; [style setLineBreakMode:NSLineBreakByWordWrapping];  UIFont *font1 = [UIFont fontWithName:@"HelveticaNeue-Medium" size:20.0f]; UIFont *font2 = [UIFont fontWithName:@"HelveticaNeue-Light"  size:20.0f]; NSDictionary *dict1 = @{NSUnderlineStyleAttributeName:@(NSUnderlineStyleSingle),                         NSFontAttributeName:font1,                         NSParagraphStyleAttributeName:style}; // Added line NSDictionary *dict2 = @{NSUnderlineStyleAttributeName:@(NSUnderlineStyleNone),                         NSFontAttributeName:font2,                         NSParagraphStyleAttributeName:style}; // Added line  NSMutableAttributedString *attString = [[NSMutableAttributedString alloc] init]; [attString appendAttributedString:[[NSAttributedString alloc] initWithString:@"LINE 1\n"    attributes:dict1]]; [attString appendAttributedString:[[NSAttributedString alloc] initWithString:@"line 2"      attributes:dict2]]; [self.resolveButton setAttributedTitle:attString forState:UIControlStateNormal]; [[self.resolveButton titleLabel] setNumberOfLines:0]; [[self.resolveButton titleLabel] setLineBreakMode:NSLineBreakByWordWrapping]; 

Note that I only added the lines that define the NSParagraphStyleAttributeName.. everything else is the same.. and this is what I get for the button:

enter image description here

And here it is in Swift 3.0

let style = NSMutableParagraphStyle() style.alignment = .center style.lineBreakMode = .byWordWrapping  guard     let font1 = UIFont(name: "HelveticaNeue-Medium", size: 20),     let font2 = UIFont(name: "HelveticaNeue-Light", size: 20)  else { return }  let dict1:[String:Any] = [     NSUnderlineStyleAttributeName:NSUnderlineStyle.styleSingle.rawValue,     NSFontAttributeName:font1,     NSParagraphStyleAttributeName:style ]  let dict2:[String:Any] = [     NSUnderlineStyleAttributeName:NSUnderlineStyle.styleNone.rawValue,     NSFontAttributeName:font2,     NSParagraphStyleAttributeName:style ]  let attString = NSMutableAttributedString() attString.append(NSAttributedString(string: "LINE 1", attributes: dict1)) attString.append(NSAttributedString(string: "line 2", attributes: dict2))  button.setAttributedTitle(attString, for: .normal) button.titleLabel?.numberOfLines = 0 button.titleLabel?.lineBreakMode = .byWordWrapping 
like image 75
ccwasden Avatar answered Sep 26 '22 02:09

ccwasden