UIButton上的iOS NSAttributedString

时间:2013-07-19 21:50:20

标签: ios uibutton nsattributedstring

我正在使用 iOS 6 ,因此归因字符串应该易于使用,对吧?嗯......没那么多。

我想做什么:

使用UIButton的自定义子类(它不会对titleLabel执行任何自定义操作),我希望有一个多行,属性标题:

  1. 第一行的全部大写(我意识到这不属于属性)
  2. 第一行
  3. 粗体
  4. 第一行
  5. 带下划线
  6. 第二行“正常”重量
  7. 第二行没有下划线
  8. 以两行为中心
  9. 到目前为止,我已经能够得到#1到5(至少,我以为我做了,但是目前的测试会产生多行文字的错误),但当我尝试做某事时(任何事情! )要使文本居中,我的应用程序不断崩溃。当我试图让所有6个项目工作时(通过各种方法),我得到以下崩溃/错误:

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

    根据我的尝试,看来我可以选择以下选项之一,但不能同时选择:

    1. 多行,居中的标签
    2. 属性标签
    3. 如果我必须,我可以与其他人生活在一起,但我无法相信我不能拥有一个看似相当简单的概念。

      有人可以告诉我我的错误吗?

      这是我正在尝试的代码的最后一次迭代:

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

3 个答案:

答案 0 :(得分:92)

在我看来,你忘了在你的代码中使用你设置的“样式”对象..你只是实例化它。您应该修改您的代码,如下所示:

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

请注意,我只添加了定义NSParagraphStyleAttributeName的行..其他一切都相同..这就是我得到的按钮:

enter image description here

这里是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

答案 1 :(得分:5)

使用Swift 4,您可以使用下面的UIButton子类实现来解决您的问题:

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")
    }

}

用法:

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])
    }

}

如果您确实需要system类型的按钮,则可以使用以下代码:

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
    }

}

用法:

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])
    }

}

下面的两个屏幕截图显示了UIButton子类(左侧)和system类型按钮(右侧)的结果显示:

enter image description here

答案 2 :(得分:0)

UIButton中标题为NSAttributedString的两行Swift 5.1

func customizeSubscribeButton() {
    subscribeButton.titleLabel?.numberOfLines = 2
    let title = NSMutableAttributedString()
    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.alignment = .center
    let part1 = NSAttributedString(string: "SUBSCRIBE FOR 12 MONTH\n",
                                   attributes: [NSAttributedString.Key.foregroundColor: UIColor.white,
                                                NSAttributedString.Key.font: UIFont.systemFont(ofSize: 24, weight: .semibold),
                                                NSAttributedString.Key.paragraphStyle: paragraphStyle])
    let part2 = NSAttributedString(string: "999.00 RUB ECONOMY 85%",
                                   attributes: [NSAttributedString.Key.foregroundColor: UIColor.white,
                                                NSAttributedString.Key.font: UIFont.systemFont(ofSize: 12, weight: .light),
                                                NSAttributedString.Key.paragraphStyle: paragraphStyle])
    title.append(part1)
    title.append(part2)
    subscribeButton.setAttributedTitle(title, for: .normal)
}