ios 在 UILabel.attributedText 中制作链接 *not* 蓝色和 *not* 下划线
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15381028/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Make link in UILabel.attributedText *not* blue and *not* underlined
提问by Ramsel
I want some words within my OHAttributedLabel to be links, but I want them to be colors other than blue and I don't want the underline.
我希望我的 OHAttributedLabel 中的一些词是链接,但我希望它们是蓝色以外的颜色,我不想要下划线。
This is giving me a blue link with underlined text:
这给了我一个带有下划线文本的蓝色链接:
-(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;
}
Since I'm using OHAttributedLabel, I also tried using the methods in it's NSAttributedString+Attributes.hcategory, but those return blue underlined links as well:
由于我使用的是 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;
}
If I comment out the line setting the links in each version, the text gets colored to what I pass in - that works. It just seems like setting the link is overriding this and turning it back to blue.
如果我注释掉每个版本中设置链接的行,文本会根据我传入的内容着色 - 有效。似乎设置链接会覆盖它并将其变回蓝色。
Unfortunately the apple docs page I found shows how to set the link text to blue and underline it, exactly what I don't need: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/AttributedStrings/Tasks/ChangingAttrStrings.html
不幸的是,我发现的苹果文档页面显示了如何将链接文本设置为蓝色并在其下划线,这正是我不需要的:https: //developer.apple.com/library/content/documentation/Cocoa/Conceptual/AttributedStrings/任务/ChangingAttrStrings.html
回答by Ramsel
So I ended up using TTTAttributedLabel:
所以我最终使用了 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];
}
I found that OHAttributedLabelactually does have methods to set links and declare colors and underline styles for those links. However, I wanted the links to be different colors based on a parameter. TTTAttributedLabelallows this by letting you set it's linkAttributesproperty for each link you create.
我发现OHAttributedLabel实际上确实有方法来设置链接并为这些链接声明颜色和下划线样式。但是,我希望链接根据参数具有不同的颜色。TTTAttributedLabel通过让您linkAttributes为您创建的每个链接设置它的属性来允许此操作。
回答by kwahn
I am using TTTAttributedLabel. I wanted to change the color of the linked text, and keep it underlined. Pim's answer looked great, but didn't work for me. Here's what did work:
我正在使用TTTAttributedLabel。我想更改链接文本的颜色,并保留下划线。Pim 的回答看起来不错,但对我不起作用。这是有效的:
label.linkAttributes = @{ (id)kCTForegroundColorAttributeName: [UIColor magentaColor],
(id)kCTUnderlineStyleAttributeName : [NSNumber numberWithInt:NSUnderlineStyleSingle] };
Note: if you don't want the text underlined, then remove the kCTUnderlineStyleAttributeName key from the dictionary.
注意:如果您不希望文本带有下划线,则从字典中删除 kCTUnderlineStyleAttributeName 键。
回答by Pim
Here's is my improved version of Ramsel's already great answer. I believe it's much more readable, and I hope it will come to good use.
这是我对 Ramsel 已经很好的答案的改进版本。我相信它更具可读性,我希望它会得到很好的使用。
label.linkAttributes = @{ NSForegroundColorAttributeName: [UIColor whiteColor],
NSUnderlineStyleAttributeName: [NSNumber numberWithInt:NSUnderlineStyleSingle] };
Here's a list of other attibute names.
回答by Lucas Chwe
If you're using a UITextView, you might have to change the tintColorproperty to change the link color.
如果您使用的是UITextView,则可能需要更改该tintColor属性以更改链接颜色。
回答by pchelnikov
Swift 2.3 example for TTTAttributedLabel:
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)
]
Swift 4
斯威夫特 4
yourLabel.linkAttributes = [
.foregroundColor: UIColor.grayColor(),
.underlineStyle: NSNumber(value: true)
]
yourLabel.activeLinkAttributes = [
.foregroundColor: UIColor.grayColor().withAlphaComponent(0.7),
.underlineStyle: NSNumber(value: false)
]
回答by Sirens
If you're like me and really don't want to use TTT (or need it in your own custom implementation where you're drawing in other weird ways):
如果你像我一样并且真的不想使用 TTT(或者在你自己的自定义实现中需要它,你以其他奇怪的方式绘制):
First, subclass NSLayoutManager and then override as follows:
首先,将 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];
}
This is more or less telling the layout manager to actually respect NSForegroundColorAttributeNamefrom your attributed string alwaysinstead of the weirdness Apple has internally for links.
这或多或少告诉布局管理器始终尊重NSForegroundColorAttributeName您的属性字符串,而不是 Apple 内部对链接的奇怪之处。
If all you need to do is get a layout manager which draws correctly (as I needed), you can stop here. If you need an actually UILabel, it's painful but possible.
如果您需要做的只是获得一个可以正确绘制的布局管理器(如我所需要),您可以到此为止。如果你需要一个真正的 UILabel,这很痛苦,但也是可能的。
First, again, subclass UILabel and slap in all of these methods.
首先,再次继承所有这些方法的 UILabel 和 slap。
- (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];
}
Shamelessly taken from here. Incredibly work on the original author's part for working this all out.
无耻地从这里拿走。令人难以置信的是,原作者的部分工作完成了这一切。
回答by Tul
For Swift 3 following way worked out for me using TTTAttributedLabel:
对于 Swift 3,以下方法适合我使用TTTAttributedLabel:
1) Add a label on the storyboard and define its class to be TTTAttributedLabel
1)在storyboard上添加一个标签,并定义它的类为 TTTAttributedLabel
2) In code define
@IBOutlet var termsLabel: TTTAttributedLabel!
2) 在代码中定义
@IBOutlet var termsLabel: TTTAttributedLabel!
3) Then in ViewDidLoadwrite these lines
3)然后在ViewDidLoad写这些行
termsLabel.attributedText = NSAttributedString(string: "By using this app you agree to the Privacy Policy & Terms & Conditions.")
guard let labelString = termsLabel.attributedText else {
return
}
guard let privacyRange = labelString.string.range(of: "Privacy Policy") else {
return
}
guard let termsConditionRange = labelString.string.range(of: "Terms & Conditions") else {
return
}
let privacyNSRange: NSRange = labelString.string.nsRange(from: privacyRange)
let termsNSRange: NSRange = labelString.string.nsRange(from: termsConditionRange)
termsLabel.addLink(to: URL(string: "privacy"), with: privacyNSRange)
termsLabel.addLink(to: URL(string: "terms"), with: termsNSRange)
termsLabel.delegate = self
let attributedText = NSMutableAttributedString(attributedString: termsLabel.attributedText!)
attributedText.addAttributes([NSFontAttributeName : UIFont(name: "Roboto-Medium", size: 12)!], range: termsNSRange)
attributedText.addAttributes([NSFontAttributeName : UIFont(name: "Roboto-Medium", size: 12)!], range: privacyNSRange)
attributedText.addAttributes([kCTForegroundColorAttributeName as String: UIColor.orange], range: termsNSRange)
attributedText.addAttributes([kCTForegroundColorAttributeName as String: UIColor.green], range: privacyNSRange)
attributedText.addAttributes([NSUnderlineStyleAttributeName: NSUnderlineStyle.styleNone.rawValue], range: termsNSRange)
attributedText.addAttributes([NSUnderlineStyleAttributeName: NSUnderlineStyle.styleNone.rawValue], range: privacyNSRange)
termsLabel.attributedText = attributedText
4) Finally write the delegate function of TTTAttributedLabelso that you can open links on tap
4)最后编写委托函数,TTTAttributedLabel以便您可以在点击时打开链接
public func attributedLabel(_ label: TTTAttributedLabel!, didSelectLinkWith url: URL!) {
switch url.absoluteString {
case "privacy":
SafariBrowser.open("http://google.com", presentingViewController: self)
case "terms":
SafariBrowser.open("http://google.com", presentingViewController: self)
default:
break
}
}
Update for Swift 4.2
Swift 4.2 更新
For Swift 4.2, there are some changes in step 3, all other steps would remain same as above:
对于 Swift 4.2,步骤 3 中有一些更改,所有其他步骤将保持与上述相同:
3) In ViewDidLoadwrite these lines
3)在ViewDidLoad写这些行
termsLabel.attributedText = NSAttributedString(string: "By using this app you agree to the Privacy Policy & Terms & Conditions.")
guard let labelString = termsLabel.attributedText else {
return
}
guard let privacyRange = labelString.string.range(of: "Privacy Policy") else {
return
}
guard let termsConditionRange = labelString.string.range(of: "Terms & Conditions") else {
return
}
let privacyNSRange: NSRange = labelString.string.nsRange(from: privacyRange)
let termsNSRange: NSRange = labelString.string.nsRange(from: termsConditionRange)
termsLabel.addLink(to: URL(string: "privacy"), with: privacyNSRange)
termsLabel.addLink(to: URL(string: "terms"), with: termsNSRange)
termsLabel.delegate = self
let attributedText = NSMutableAttributedString(attributedString: termsLabel.attributedText!)
attributedText.addAttributes([NSAttributedString.Key.font : UIFont(name: "Roboto-Regular", size: 12)!], range: termsNSRange)
attributedText.addAttributes([NSAttributedString.Key.font : UIFont(name: "Roboto-Regular", size: 12)!], range: privacyNSRange)
attributedText.addAttributes([kCTForegroundColorAttributeName as NSAttributedString.Key : UIColor.orange], range: termsNSRange)
attributedText.addAttributes([kCTForegroundColorAttributeName as NSAttributedString.Key : UIColor.green], range: privacyNSRange)
attributedText.addAttributes([NSAttributedString.Key.underlineStyle: 0], range: termsNSRange)
attributedText.addAttributes([NSAttributedString.Key.underlineStyle: 0], range: privacyNSRange)
回答by Dana Wheeler
Swift 3 example for TTTAttributedLabel:
Swift 3 示例TTTAttributedLabel:
yourLabel.linkAttributes = [
NSForegroundColorAttributeName: UIColor.green,
NSUnderlineStyleAttributeName: NSNumber(value: NSUnderlineStyle.styleNone.rawValue)
]
yourLabel.activeLinkAttributes = [
NSForegroundColorAttributeName: UIColor.green,
NSUnderlineStyleAttributeName: NSNumber(value: NSUnderlineStyle.styleDouble.rawValue)
]
回答by pableiros
For Swift 3 using TTTAttributedLabel
对于 Swift 3 使用 TTTAttributedLabel
let title: NSString = "Fork me on GitHub!"
var attirutedDictionary = NSMutableDictionary(dictionary:attributedLabel.linkAttributes)
attirutedDictionary[NSForegroundColorAttributeName] = UIColor.red
attirutedDictionary[NSUnderlineStyleAttributeName] = NSNumber(value: NSUnderlineStyle.styleNone.rawValue)
attributedLabel.attributedText = NSAttributedString(string: title as String)
attributedLabel.linkAttributes = attirutedDictionary as! [AnyHashable: Any]
let range = subtitleTitle.range(of: "me")
let url = URL(string: "http://github.com/mattt/")
attributedLabel.addLink(to: url, with: range)
回答by guru
Swift 4.0 :
斯威夫特 4.0:
Short and simple
简短而简单
let LinkAttributes = NSMutableDictionary(dictionary: testLink.linkAttributes)
LinkAttributes[NSAttributedStringKey.underlineStyle] = NSNumber(value: false)
LinkAttributes[NSAttributedStringKey.foregroundColor] = UIColor.black // Whatever your label color
testLink.linkAttributes = LinkAttributes as NSDictionary as! [AnyHashable: Any]

