根据其原始纯文本状态创建 UIButton 属性标题

Creating UIButton attributed title based on its original plain text state

我正在尝试创建一个 UIButton 的子类来强制执行文本字距调整。因此,当我在 Interface Builder 中构建按钮时,设置文本颜色(使用纯文本)我希望能够从普通 titleLabel 实例中获取现有文本、颜色、段落样式和字体并将其转换为具有相同属性的属性标签。

我写了两个我认为可能有帮助的类别:

+ (NSMutableAttributedString*)attributedStringWithTitle:(NSString*)title fromExistingAttributedString:(NSAttributedString*)attributedString
{
    NSDictionary *attributes = [attributedString attributesAtIndex:0 effectiveRange:NULL];
    return [[NSMutableAttributedString alloc] initWithString:title attributes:attributes];
}

+ (NSMutableAttributedString*)attributedStringWithTitle:(NSString*)title fromPlainTextLabel:(UILabel*)label
{
    NSMutableAttributedString* mutableTitle = [[NSMutableAttributedString alloc] initWithString:title];
    [mutableTitle addAttribute:NSFontAttributeName value:label.font range:[mutableTitle fullRange]];
    [mutableTitle addAttribute:NSForegroundColorAttributeName value:label.textColor range:[mutableTitle fullRange]];
    NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
    style.alignment = label.textAlignment;
    [mutableTitle addAttribute:NSParagraphStyleAttributeName value:style range:[mutableTitle fullRange]];
    return mutableTitle;
}

然后在我的 UIButton 子类中,我像这样覆盖它们:

- (void)setAttributedTitle:(NSAttributedString *)title forState:(UIControlState)state
{
    NSMutableAttributedString* mutableTitle = [title mutableCopy];
    [mutableTitle addAttributes:@{NSKernAttributeName: @(kDefaultKerning)} range:[mutableTitle fullRange]];
    [super setAttributedTitle:mutableTitle forState:state];
    [self setNeedsDisplay];
}

- (void)setTitle:(NSString *)title forState:(UIControlState)state
{
    NSMutableAttributedString* mutableTitle;
    if ([self attributedTitleForState:state]) {
        mutableTitle = [NSMutableAttributedString attributedStringWithTitle:title fromExistingAttributedString:[self attributedTitleForState:state]];
    } else {
        mutableTitle = [NSMutableAttributedString attributedStringWithTitle:title fromPlainTextLabel:self.titleLabel];
    }
    [self setAttributedTitle:mutableTitle forState:state];    
}

但有些东西不起作用 - 特别值得注意的是,[self attributedTitleForState:state][self titleForState:state] 似乎总是为零。在我看来,在 Interface Builder 中设置属性的方式有些不连贯,因为当文本通过 OK 时,它缺少所有样式。

终于成功了。事实证明,纯文本 UIButton 的多个属性位于多个位置。有些有直接从 UIButton 检索的辅助方法,有些没有。

  • 字体:self.titleLabel.font(无辅助方法)
  • 颜色:[self titleColorForState:state]
  • 正文:[self titleForState:state]
  • 属性文本:[self attributedTitleForState]

并且纯文本 UIButton 默认情况下没有任何文本对齐方式,因为那是 controlled by content horizontal alignment

因此,我更改了我的辅助方法(第一个是相同的,但我不得不更改第二个):

+ (NSMutableAttributedString*)attributedStringWithTitle:(NSString*)title fromExistingAttributedString:(NSAttributedString*)attributedString
{
    NSDictionary *attributes = [attributedString attributesAtIndex:0 effectiveRange:NULL];
    return [[NSMutableAttributedString alloc] initWithString:title attributes:attributes];
}

+ (NSMutableAttributedString*)attributedStringWithTitle:(NSString*)title font:(UIFont*)font color:(UIColor*)color 
{
    NSMutableAttributedString* mutableTitle = [[NSMutableAttributedString alloc] initWithString:title];
    [mutableTitle addAttribute:NSFontAttributeName value:font range:[mutableTitle fullRange]];
    [mutableTitle addAttribute:NSForegroundColorAttributeName value:color range:[mutableTitle fullRange]];
    NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
    [mutableTitle addAttribute:NSParagraphStyleAttributeName value:style range:[mutableTitle fullRange]];
    return mutableTitle;
}

我是这样实现的:

- (void)setAttributedTitle:(NSAttributedString *)title forState:(UIControlState)state
{
    NSMutableAttributedString* mutableTitle = [title mutableCopy];
    [mutableTitle addAttributes:@{NSKernAttributeName: @(kDefaultKerning)} range:[mutableTitle fullRange]];
    [super setAttributedTitle:mutableTitle forState:state];
    [self setNeedsDisplay];
}

- (void)setTitle:(NSString *)title forState:(UIControlState)state
{
    NSMutableAttributedString* mutableTitle;
    if ([self attributedTitleForState:state]) {
        mutableTitle = [NSMutableAttributedString attributedStringWithTitle:title fromExistingAttributedString:[self attributedTitleForState:state]];
    } else {
        mutableTitle = [NSMutableAttributedString attributedStringWithTitle:title font:self.titleLabel.font color:[self titleColorForState:state]];
    }
    [self setAttributedTitle:mutableTitle forState:state];
}