2013-07-19 19 views
48

Używam iOS 6, więc przypisane ciągi powinny być łatwe w użyciu, prawda? Cóż ... nie tak bardzo.NSAttributedString iOS na UIButtonie

Co chcę zrobić:

Korzystanie niestandardową podklasę UIButton (nie robi nic zwyczaj titleLabel), chciałbym mieć kilka linii, nadany tytuł, który brzmi:

  1. Wszystkie czapki (zdaję sobie sprawę, że nie jest część atrybutów) na pierwszej linii
  2. pogrubione na pierwszej linii
  3. podkreślone na pierwszej linii
  4. „Normal” ciężar na drugiej linii
  5. dla podkreślone w drugim wierszu
  6. skoncentrowane na obu liniach

byłem w stanie uzyskać # 's 1 do 5 do tej pory (przynajmniej myślałem, że tak, ale obecne testy przynoszą błędy z tekstem wielowierszowym), ale kiedy próbowałem coś zrobić (cokolwiek!), aby uzyskać wycentrowanie tekstu, moja aplikacja się zawiesza. Kiedy próbuję uzyskać wszystkie elementy robocze 6 (różnymi metodami), pojawia się następujący błąd:/awarii

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.' 

W oparciu o to, co próbowałem, wydaje się, że mogę mieć jedną z następujących opcji, ale nie oba:

  1. a multi-linia, skupione etykieta
  2. nadana etykieta

mogę żyć z jednej lub drugiej strony, gdybym koniecznością, ale nie mogę uwierzyć, że nie mogę mieć tego, co wydaje się dość prostolinijną koncepcją.

Czy ktoś może mi powiedzieć, co mam nie tak?

Oto ostatnia iteracja kodu próbuję:

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]; 
+1

Co powiesz na stylizację UILabel i dodanie jej do przycisku? – JeffRegan

+0

Czy "titleLabel' nie ma być" UILabel "? Sądzę, że mógłbym to zrobić, ale nadal uważam, że to większy młotek niż POWINNY być konieczny. – mbm29414

+0

To iOS, nic nie ma sensu ... Dzieciaku. Pomyślałem z NSMutableAttributedString jakiś czas temu i to było tylko bóle głowy. Moją radą byłoby, aby wszystko było tak proste i łatwe, jak to tylko możliwe. – JeffRegan

Odpowiedz

87

Wygląda mi na to, że zapomniał w kodzie, aby użyć „styl” obiekt, który ustanowiony .. po prostu to instancja . Należy zmodyfikować kod, aby wyglądać tak:

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]; 

pamiętać, że tylko dodatkiem linii definiujących NSParagraphStyleAttributeName .. wszystko inne jest takie samo .. i to, co mam na przycisku:

enter image description here

I tutaj jest w 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 
+0

Kiedy używam przypisanego tekstu, czy ktoś ma rozwiązanie? –

+0

http://stackoverflow.com/questions/24525224/programmatically-change-title-color-of-uibutton-whose-title-set-as-attributed-in, dostałem odpowiedź tutaj. –

+0

Jak dodać kolor? –

2

Z Swift 4, można użyć realizację UIButton podklasy poniżej, aby rozwiązać swój problem:

import UIKit 

class CustomButton: UIButton { 

    required init(title: String, subtitle: String) { 
     super.init(frame: CGRect.zero) 

     let style = NSMutableParagraphStyle() 
     style.alignment = NSTextAlignment.center 
     style.lineBreakMode = NSLineBreakMode.byWordWrapping 

     let titleAttributes: [NSAttributedStringKey : Any] = [ 
      NSAttributedStringKey.underlineStyle : NSUnderlineStyle.styleSingle.rawValue, 
      NSAttributedStringKey.font : UIFont.preferredFont(forTextStyle: UIFontTextStyle.largeTitle), 
      NSAttributedStringKey.paragraphStyle : style 
     ] 
     let subtitleAttributes = [ 
      NSAttributedStringKey.font : UIFont.preferredFont(forTextStyle: UIFontTextStyle.body), 
      NSAttributedStringKey.paragraphStyle : style 
     ] 

     let attributedString = NSMutableAttributedString(string: title, attributes: titleAttributes) 
     attributedString.append(NSAttributedString(string: "\n")) 
     attributedString.append(NSAttributedString(string: subtitle, attributes: subtitleAttributes)) 

     setAttributedTitle(attributedString, for: UIControlState.normal) 
     titleLabel?.numberOfLines = 0 
     titleLabel?.lineBreakMode = NSLineBreakMode.byWordWrapping 
    } 

    required init?(coder aDecoder: NSCoder) { 
     fatalError("init(coder:) has not been implemented") 
    } 

} 

Zastosowanie:

import UIKit 

class ViewController: UIViewController { 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     let button = CustomButton(title: "Title", subtitle: "Subtitle") 
     button.translatesAutoresizingMaskIntoConstraints = false 
     view.addSubview(button) 

     let horizontalConstraint = button.centerXAnchor.constraint(equalTo: view.centerXAnchor) 
     let verticalConstraint = button.centerYAnchor.constraint(equalTo: view.centerYAnchor) 
     NSLayoutConstraint.activate([horizontalConstraint, verticalConstraint]) 
    } 

} 

jako alternatywa, jeśli naprawdę potrzebujesz przycisku typu system, można użyć następującego kodu:

import UIKit 

extension UIButton { 

    static func customSystemButton(title: String, subtitle: String) -> UIButton {    
     let style = NSMutableParagraphStyle() 
     style.alignment = NSTextAlignment.center 
     style.lineBreakMode = NSLineBreakMode.byWordWrapping 

     let titleAttributes: [NSAttributedStringKey : Any] = [ 
      NSAttributedStringKey.underlineStyle : NSUnderlineStyle.styleSingle.rawValue, 
      NSAttributedStringKey.font : UIFont.preferredFont(forTextStyle: UIFontTextStyle.largeTitle), 
      NSAttributedStringKey.paragraphStyle : style 
     ] 
     let subtitleAttributes = [ 
      NSAttributedStringKey.font : UIFont.preferredFont(forTextStyle: UIFontTextStyle.body), 
      NSAttributedStringKey.paragraphStyle : style 
     ] 

     let attributedString = NSMutableAttributedString(string: title, attributes: titleAttributes) 
     attributedString.append(NSAttributedString(string: "\n")) 
     attributedString.append(NSAttributedString(string: subtitle, attributes: subtitleAttributes)) 

     let button = UIButton(type: UIButtonType.system) 
     button.setAttributedTitle(attributedString, for: UIControlState.normal) 
     button.titleLabel?.numberOfLines = 0 
     button.titleLabel?.lineBreakMode = NSLineBreakMode.byWordWrapping 

     return button 
    } 

} 

Zastosowanie:

import UIKit 

class ViewController: UIViewController { 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     let button = UIButton.customSystemButton(title: "Title", subtitle: "Subtitle") 
     button.translatesAutoresizingMaskIntoConstraints = false 
     view.addSubview(button) 

     let horizontalConstraint = button.centerXAnchor.constraint(equalTo: view.centerXAnchor) 
     let verticalConstraint = button.centerYAnchor.constraint(equalTo: view.centerYAnchor) 
     NSLayoutConstraint.activate([horizontalConstraint, verticalConstraint]) 
    } 

} 

Dwa zrzuty ekranu poniżej przedstawiają wyświetlacz wynik dla UIButton podklasy (po lewej) oraz dla przycisk typu system (po prawej):

enter image description here

Powiązane problemy