在UILabel.attributedText中建立链接*不是*蓝色,*不是*带下划线

Ram*_*sel 37 xcode objective-c nsattributedstring ios

我希望我的OHAttributedLabel中的一些单词是链接,但我希望它们是蓝色以外的颜色,我不想要下划线.

这给了我一个带下划线文字的蓝色链接:

 -(void)createLinkFromWord:(NSString*)word withColor:(UIColor*)color atRange:(NSRange)range{

    NSMutableAttributedString* mutableAttributedText = [self.label.attributedText mutableCopy];   

    [mutableAttributedText beginEditing];
    [mutableAttributedText addAttribute:kOHLinkAttributeName
                   value:[NSURL URLWithString:@"http://www.somewhere.net"]
                   range:range];

    [mutableAttributedText addAttribute:(id)kCTForegroundColorAttributeName
                   value:color
                   range:range];

    [mutableAttributedText addAttribute:(id)kCTUnderlineStyleAttributeName
                   value:[NSNumber numberWithInt:kCTUnderlineStyleNone]
                   range:range];
    [mutableAttributedText endEditing];


    self.label.attributedText = mutableAttributedText;

}
Run Code Online (Sandbox Code Playgroud)

由于我正在使用OHAttributedLabel,我也尝试使用它的NSAttributedString+Attributes.h类别中的方法,但那些返回蓝色下划线链接:

-(void)createLinkFromWord:(NSString*)word withColor:(UIColor*)color atRange:(NSRange)range{

NSMutableAttributedString* mutableAttributedText = [self.label.attributedText mutableCopy];

[mutableAttributedText setLink:[NSURL URLWithString:@"http://www.somewhere.net"] range:range];
[mutableAttributedText setTextColor:color range:range];
[mutableAttributedText setTextUnderlineStyle:kCTUnderlineStyleNone range:range];

self.label.attributedText = mutableAttributedText;
}
Run Code Online (Sandbox Code Playgroud)

如果我注释掉在每个版本中设置链接的行,那么文本就会变成我传入的内容 - 这是有效的.似乎设置链接覆盖了这个并将其转回蓝色.

不幸的是,我发现的apple docs页面显示了如何将链接文本设置为蓝色并加下划线,正是我不需要的:https: //developer.apple.com/library/content/documentation/Cocoa/Conceptual/AttributedStrings/任务/ ChangingAttrStrings.html

Ram*_*sel 62

所以我最终使用了TTTAttributedLabel:

-(void)createLinkFromWord:(NSString*)word withColor:(UIColor*)color atRange:(NSRange)range{
    NSMutableAttributedString* newTextWithLinks = [self.label.attributedText mutableCopy];
    NSURL *url = [NSURL URLWithString:@"http://www.reddit.com"];
    self.label.linkAttributes = @{NSForegroundColorAttributeName: color, 
                                   NSUnderlineStyleAttributeName: @(NSUnderlineStyleNone)};
    [self.label addLinkToURL:url withRange:range];
}
Run Code Online (Sandbox Code Playgroud)

我发现OHAttributedLabel实际上确实有方法来设置链接并为这些链接声明颜色和下划线样式.但是,我希望链接基于参数是不同的颜色.TTTAttributedLabel允许您linkAttributes为您创建的每个链接设置它的属性.

  • 还要确保在添加标签链接之前设置`linkAttributes`. (14认同)
  • 除了某些github项目,没有其他方法可以设置链接颜色吗?linkAttributes属性不适用于UILabel。 (2认同)

kwa*_*ahn 23

我正在使用TTTAttributedLabel.我想改变链接文本的颜色,并保持下划线.Pim的答案看起来很棒,但对我来说不起作用.这是做了什么工作:

label.linkAttributes = @{ (id)kCTForegroundColorAttributeName: [UIColor magentaColor],
                           (id)kCTUnderlineStyleAttributeName : [NSNumber numberWithInt:NSUnderlineStyleSingle] };
Run Code Online (Sandbox Code Playgroud)

注意:如果您不希望文本带下划线,则从字典中删除kCTUnderlineStyleAttributeName键.


Pim*_*Pim 22

这是我改进版的Ramsel已经很好的答案.我相信它更具可读性,我希望它会得到很好的利用.

label.linkAttributes = @{ NSForegroundColorAttributeName: [UIColor whiteColor],
                          NSUnderlineStyleAttributeName: [NSNumber numberWithInt:NSUnderlineStyleSingle] };
Run Code Online (Sandbox Code Playgroud)

是其他名称的列表.

  • UILabel 没有 linkAttributes 属性 (3认同)

Luc*_*hwe 8

如果您使用的是a UITextView,则可能需要更改tintColor属性以更改链接颜色.


pch*_*kov 6

Swift 2.3示例TTTAttributedLabel:

yourLabel.linkAttributes       = [
    NSForegroundColorAttributeName: UIColor.grayColor(),
    NSUnderlineStyleAttributeName: NSNumber(bool: true)
]
yourLabel.activeLinkAttributes = [
    NSForegroundColorAttributeName: UIColor.grayColor().colorWithAlphaComponent(0.8),
    NSUnderlineStyleAttributeName: NSNumber(bool: false)
]
Run Code Online (Sandbox Code Playgroud)

斯威夫特4

yourLabel.linkAttributes = [
    .foregroundColor: UIColor.grayColor(),
    .underlineStyle: NSNumber(value: true)
]
yourLabel.activeLinkAttributes = [
    .foregroundColor: UIColor.grayColor().withAlphaComponent(0.7),
    .underlineStyle: NSNumber(value: false)
]
Run Code Online (Sandbox Code Playgroud)

  • UILabel 没有 linkAttributes (2认同)

Sir*_*ens 5

如果您像我一样并且真的不想使用 TTT(或者在您自己的自定义实现中需要它,您以其他奇怪的方式进行绘制):

首先,继承 NSLayoutManager ,然后重写如下:

- (void)showCGGlyphs:(const CGGlyph *)glyphs 
           positions:(const CGPoint *)positions 
               count:(NSUInteger)glyphCount
                font:(UIFont *)font 
              matrix:(CGAffineTransform)textMatrix 
          attributes:(NSDictionary *)attributes
           inContext:(CGContextRef)graphicsContext
{
   UIColor *foregroundColor = attributes[NSForegroundColorAttributeName];

   if (foregroundColor)
   {
      CGContextSetFillColorWithColor(graphicsContext, foregroundColor.CGColor);
   }

   [super showCGGlyphs:glyphs 
             positions:positions 
                 count:glyphCount 
                  font:font 
                matrix:textMatrix 
            attributes:attributes 
             inContext:graphicsContext];
}
Run Code Online (Sandbox Code Playgroud)

这或多或少告诉布局管理器始终尊重NSForegroundColorAttributeName的属性字符串,而不是苹果内部对链接的怪异。

如果您需要做的只是获得一个可以正确绘制的布局管理器(如我所需要的),那么您可以到此为止。如果您确实需要一个 UILabel,这很痛苦但也是可能的。

首先,再次对 UILabel 进行子类化并添加所有这些方法。

- (NSTextStorage *)textStorage
{
   if (!_textStorage)
   {
      _textStorage = [[NSTextStorage alloc] init];
      [_textStorage addLayoutManager:self.layoutManager];
      [self.layoutManager setTextStorage:_textStorage];
   }

   return _textStorage;
}

- (NSTextContainer *)textContainer
{
   if (!_textContainer)
   {
      _textContainer = [[NSTextContainer alloc] init];
      _textContainer.lineFragmentPadding = 0;
      _textContainer.maximumNumberOfLines = self.numberOfLines;
      _textContainer.lineBreakMode = self.lineBreakMode;
      _textContainer.widthTracksTextView = YES;
      _textContainer.size = self.frame.size;

      [_textContainer setLayoutManager:self.layoutManager];
   }

   return _textContainer;
}

- (NSLayoutManager *)layoutManager
{
   if (!_layoutManager)
   {
      // Create a layout manager for rendering
      _layoutManager = [[PRYLayoutManager alloc] init];
      _layoutManager.delegate = self;
      [_layoutManager addTextContainer:self.textContainer];
   }

   return _layoutManager;
}

- (void)layoutSubviews
{
   [super layoutSubviews];

   // Update our container size when the view frame changes
   self.textContainer.size = self.bounds.size;
}

- (void)setFrame:(CGRect)frame
{
   [super setFrame:frame];

   CGSize size = frame.size;
   size.width = MIN(size.width, self.preferredMaxLayoutWidth);
   size.height = 0;
   self.textContainer.size = size;
}

- (void)setBounds:(CGRect)bounds
{
   [super setBounds:bounds];

   CGSize size = bounds.size;
   size.width = MIN(size.width, self.preferredMaxLayoutWidth);
   size.height = 0;
   self.textContainer.size = size;
}

- (void)setPreferredMaxLayoutWidth:(CGFloat)preferredMaxLayoutWidth
{
   [super setPreferredMaxLayoutWidth:preferredMaxLayoutWidth];

   CGSize size = self.bounds.size;
   size.width = MIN(size.width, self.preferredMaxLayoutWidth);
   self.textContainer.size = size;
}
- (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)numberOfLines
{
  // Use our text container to calculate the bounds required. First save our
  // current text container setup
  CGSize savedTextContainerSize = self.textContainer.size;
  NSInteger savedTextContainerNumberOfLines = self.textContainer.maximumNumberOfLines;

  // Apply the new potential bounds and number of lines
  self.textContainer.size = bounds.size;
  self.textContainer.maximumNumberOfLines = numberOfLines;

  // Measure the text with the new state
  CGRect textBounds;
  @try
  {
      NSRange glyphRange = [self.layoutManager 
                            glyphRangeForTextContainer:self.textContainer];
      textBounds = [self.layoutManager boundingRectForGlyphRange:glyphRange
                                       inTextContainer:self.textContainer];

      // Position the bounds and round up the size for good measure
      textBounds.origin = bounds.origin;
      textBounds.size.width = ceilf(textBounds.size.width);
      textBounds.size.height = ceilf(textBounds.size.height);
  }
  @finally
  {
      // Restore the old container state before we exit under any circumstances
      self.textContainer.size = savedTextContainerSize;
      self.textContainer.maximumNumberOfLines = savedTextContainerNumberOfLines;
   }

   return textBounds;
}

- (void)setAttributedText:(NSAttributedString *)attributedText
{
    // Pass the text to the super class first
    [super setAttributedText:attributedText];

    [self.textStorage setAttributedString:attributedText];
}
- (CGPoint)_textOffsetForGlyphRange:(NSRange)glyphRange
{
   CGPoint textOffset = CGPointZero;

   CGRect textBounds = [self.layoutManager boundingRectForGlyphRange:glyphRange 
                                                     inTextContainer:self.textContainer];
   CGFloat paddingHeight = (self.bounds.size.height - textBounds.size.height) / 2.0f;
   if (paddingHeight > 0)
   {
       textOffset.y = paddingHeight;
   }

   return textOffset;
}

- (void)drawTextInRect:(CGRect)rect
{
   // Calculate the offset of the text in the view
   CGPoint textOffset;
   NSRange glyphRange = [self.layoutManager glyphRangeForTextContainer:self.textContainer];
   textOffset = [self _textOffsetForGlyphRange:glyphRange];

   // Drawing code
   [self.layoutManager drawBackgroundForGlyphRange:glyphRange atPoint:textOffset];

   // for debugging the following 2 line should produce the same results
   [self.layoutManager drawGlyphsForGlyphRange:glyphRange atPoint:textOffset];
   //[super drawTextInRect:rect];
}
Run Code Online (Sandbox Code Playgroud)

无耻地从这里夺走。原作者为解决这一切付出了令人难以置信的努力。