diff --git a/Demo/YYTextDemo.xcodeproj/project.pbxproj b/Demo/YYTextDemo.xcodeproj/project.pbxproj index db1f1efa..beae7944 100644 --- a/Demo/YYTextDemo.xcodeproj/project.pbxproj +++ b/Demo/YYTextDemo.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 010A65AF261F028000753A75 /* YYTextHighlight+NSLink.m in Sources */ = {isa = PBXBuildFile; fileRef = 010A65AE261F028000753A75 /* YYTextHighlight+NSLink.m */; }; D91054861F3735D20007F224 /* Animated image support.txt in Resources */ = {isa = PBXBuildFile; fileRef = D910547B1F3735D20007F224 /* Animated image support.txt */; }; D91054871F3735D20007F224 /* YYAnimatedImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = D910547D1F3735D20007F224 /* YYAnimatedImageView.m */; }; D91054881F3735D20007F224 /* YYFrameImage.m in Sources */ = {isa = PBXBuildFile; fileRef = D910547F1F3735D20007F224 /* YYFrameImage.m */; }; @@ -38,7 +39,6 @@ D91054D71F3735E50007F224 /* YYLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = D91054BD1F3735E50007F224 /* YYLabel.m */; }; D91054D81F3735E50007F224 /* YYTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = D91054C01F3735E50007F224 /* YYTextView.m */; }; D91054DD1F3736060007F224 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D91054DA1F3736060007F224 /* AppDelegate.m */; }; - D91054DE1F3736060007F224 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D91054DC1F3736060007F224 /* ViewController.m */; }; D91054F61F3736700007F224 /* CALayer+YYAdd.m in Sources */ = {isa = PBXBuildFile; fileRef = D91054E11F3736700007F224 /* CALayer+YYAdd.m */; }; D91054F71F3736700007F224 /* NSBundle+YYAdd.m in Sources */ = {isa = PBXBuildFile; fileRef = D91054E31F3736700007F224 /* NSBundle+YYAdd.m */; }; D91054F81F3736700007F224 /* NSData+YYAdd.m in Sources */ = {isa = PBXBuildFile; fileRef = D91054E51F3736700007F224 /* NSData+YYAdd.m */; }; @@ -82,6 +82,8 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 010A65AD261F028000753A75 /* YYTextHighlight+NSLink.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "YYTextHighlight+NSLink.h"; sourceTree = ""; }; + 010A65AE261F028000753A75 /* YYTextHighlight+NSLink.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "YYTextHighlight+NSLink.m"; sourceTree = ""; }; D910547B1F3735D20007F224 /* Animated image support.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "Animated image support.txt"; sourceTree = ""; }; D910547C1F3735D20007F224 /* YYAnimatedImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYAnimatedImageView.h; sourceTree = ""; }; D910547D1F3735D20007F224 /* YYAnimatedImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYAnimatedImageView.m; sourceTree = ""; }; @@ -144,8 +146,6 @@ D91054C01F3735E50007F224 /* YYTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYTextView.m; sourceTree = ""; }; D91054D91F3736060007F224 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; D91054DA1F3736060007F224 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; - D91054DB1F3736060007F224 /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; - D91054DC1F3736060007F224 /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; D91054E01F3736700007F224 /* CALayer+YYAdd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CALayer+YYAdd.h"; sourceTree = ""; }; D91054E11F3736700007F224 /* CALayer+YYAdd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "CALayer+YYAdd.m"; sourceTree = ""; }; D91054E21F3736700007F224 /* NSBundle+YYAdd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSBundle+YYAdd.h"; sourceTree = ""; }; @@ -306,6 +306,8 @@ D91054A81F3735E50007F224 /* YYTextRubyAnnotation.m */, D91054A91F3735E50007F224 /* YYTextRunDelegate.h */, D91054AA1F3735E50007F224 /* YYTextRunDelegate.m */, + 010A65AD261F028000753A75 /* YYTextHighlight+NSLink.h */, + 010A65AE261F028000753A75 /* YYTextHighlight+NSLink.m */, ); path = String; sourceTree = ""; @@ -360,8 +362,6 @@ D91054F51F3736700007F224 /* YYWeakProxy.m */, D91054D91F3736060007F224 /* AppDelegate.h */, D91054DA1F3736060007F224 /* AppDelegate.m */, - D91054DB1F3736060007F224 /* ViewController.h */, - D91054DC1F3736060007F224 /* ViewController.m */, D94EE9941F37304200F37AD6 /* Main.storyboard */, D94EE9971F37304200F37AD6 /* Assets.xcassets */, D94EE9991F37304200F37AD6 /* LaunchScreen.storyboard */, @@ -538,6 +538,7 @@ D91054D11F3735E50007F224 /* UIPasteboard+YYText.m in Sources */, D91054F61F3736700007F224 /* CALayer+YYAdd.m in Sources */, D91054D01F3735E50007F224 /* NSParagraphStyle+YYText.m in Sources */, + 010A65AF261F028000753A75 /* YYTextHighlight+NSLink.m in Sources */, D91054FD1F3736700007F224 /* UIView+YYAdd.m in Sources */, D91054D51F3735E50007F224 /* YYTextUtilities.m in Sources */, D91054D71F3735E50007F224 /* YYLabel.m in Sources */, @@ -546,7 +547,6 @@ D91054F81F3736700007F224 /* NSData+YYAdd.m in Sources */, D91054F71F3736700007F224 /* NSBundle+YYAdd.m in Sources */, D91054C81F3735E50007F224 /* YYTextMagnifier.m in Sources */, - D91054DE1F3736060007F224 /* ViewController.m in Sources */, D910551D1F37367B0007F224 /* YYTextAttributeExample.m in Sources */, D91055261F37367B0007F224 /* YYTextTagExample.m in Sources */, D91054C21F3735E50007F224 /* YYTextDebugOption.m in Sources */, diff --git a/Framework/YYText.xcodeproj/project.pbxproj b/Framework/YYText.xcodeproj/project.pbxproj index 4f7bb8cc..1f21b1f5 100644 --- a/Framework/YYText.xcodeproj/project.pbxproj +++ b/Framework/YYText.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 010A65B4261F04C900753A75 /* YYTextHighlight+NSLink.h in Headers */ = {isa = PBXBuildFile; fileRef = 010A65B2261F04C900753A75 /* YYTextHighlight+NSLink.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 010A65B5261F04C900753A75 /* YYTextHighlight+NSLink.m in Sources */ = {isa = PBXBuildFile; fileRef = 010A65B3261F04C900753A75 /* YYTextHighlight+NSLink.m */; }; D995E6BA1F372EC800EBEE44 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D918BFE71F372EA000106E14 /* MobileCoreServices.framework */; }; D995E6BB1F372EC800EBEE44 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D918BFE61F372E9B00106E14 /* Accelerate.framework */; }; D995E6BC1F372EC800EBEE44 /* CoreText.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D918BFE51F372E9800106E14 /* CoreText.framework */; }; @@ -65,6 +67,8 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 010A65B2261F04C900753A75 /* YYTextHighlight+NSLink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "YYTextHighlight+NSLink.h"; sourceTree = ""; }; + 010A65B3261F04C900753A75 /* YYTextHighlight+NSLink.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "YYTextHighlight+NSLink.m"; sourceTree = ""; }; D918BFD61F372E3000106E14 /* YYText.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = YYText.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D918BFDA1F372E3000106E14 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; D918BFE21F372E6800106E14 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; @@ -226,6 +230,8 @@ D995E6DC1F372ED100EBEE44 /* YYTextRubyAnnotation.m */, D995E6DD1F372ED100EBEE44 /* YYTextRunDelegate.h */, D995E6DE1F372ED100EBEE44 /* YYTextRunDelegate.m */, + 010A65B2261F04C900753A75 /* YYTextHighlight+NSLink.h */, + 010A65B3261F04C900753A75 /* YYTextHighlight+NSLink.m */, ); path = String; sourceTree = ""; @@ -284,6 +290,7 @@ D995E7011F372ED100EBEE44 /* YYTextLine.h in Headers */, D995E6F51F372ED100EBEE44 /* YYTextContainerView.h in Headers */, D995E6FF1F372ED100EBEE44 /* YYTextLayout.h in Headers */, + 010A65B4261F04C900753A75 /* YYTextHighlight+NSLink.h in Headers */, D995E7071F372ED100EBEE44 /* YYTextArchiver.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -370,6 +377,7 @@ D995E7081F372ED100EBEE44 /* YYTextArchiver.m in Sources */, D995E7101F372ED100EBEE44 /* YYTextRunDelegate.m in Sources */, D995E6F81F372ED100EBEE44 /* YYTextDebugOption.m in Sources */, + 010A65B5261F04C900753A75 /* YYTextHighlight+NSLink.m in Sources */, D995E6FA1F372ED100EBEE44 /* YYTextEffectWindow.m in Sources */, D995E7041F372ED100EBEE44 /* YYTextMagnifier.m in Sources */, D995E7181F372ED100EBEE44 /* UIView+YYText.m in Sources */, diff --git a/README.md b/README.md index cb9e9a61..e5fa4d9b 100755 --- a/README.md +++ b/README.md @@ -13,7 +13,11 @@ Powerful text framework for iOS to display and edit rich text.
Features ============== +### New +- Add support for `NSLink` +- Add `AutoLayout` support for YYTextView +### Others - UILabel and UITextView API compatible - High performance asynchronous text layout and rendering - Extended CoreText attributes with more text effects @@ -253,7 +257,7 @@ textView.dataDetectorTypes = ... textView.placeHolderText = ... textView.placeHolderTextColor = ... textView.delegate = ... -``` +``` ### Attributed text ```objc @@ -277,7 +281,7 @@ textView.attributedString = text; ``` ### Text highlight - + You can use some convenience methods to set text highlight: ```objc [text yy_setTextHighlightRange:range @@ -399,8 +403,8 @@ YYTextLayout *layout = [YYTextLayout layoutWithContainer:container text:text]; YYLabel *label = [YYLabel new]; label.size = layout.textBoundingSize; label.textLayout = layout; -``` - +``` + ### Asynchronous layout and rendering ```objc // If you have performance issues, @@ -449,7 +453,7 @@ textView.exclusionPaths = @[[UIBezierPath bezierPathWith...];,...]; textView.textContainerInset = UIEdgeInsetsMake(...); textView.verticalForm = YES/NO; ``` - + ### Text parser ```objc // 1. Create a text parser @@ -474,7 +478,7 @@ label.textParser = parser; YYTextView *textView = ... textView.textParser = parser; ``` - + ### Debug ```objc // Set a shared debug option to show text layout result. @@ -796,7 +800,7 @@ textView.dataDetectorTypes = ... textView.placeHolderText = ... textView.placeHolderTextColor = ... textView.delegate = ... -``` +``` ### 属性文本 ```objc @@ -817,7 +821,7 @@ label.attributedString = text; YYTextView *textView = [YYTextView new]; textView.frame = ... textView.attributedString = text; -``` +``` ### 文本高亮 @@ -917,7 +921,7 @@ YYLabel *label = [YYLabel new]; label.size = layout.textBoundingSize; label.textLayout = layout; ``` - + ### 文本行位置调整 ```objc // 由于中文、英文、Emoji 等字体高度不一致,或者富文本中出现了不同字号的字体, @@ -992,7 +996,7 @@ YYTextView *textView = ... textView.exclusionPaths = @[[UIBezierPath bezierPathWith...];,...]; textView.textContainerInset = UIEdgeInsetsMake(...); textView.verticalForm = YES/NO; -``` +``` ### 文本解析 ```objc @@ -1090,7 +1094,7 @@ debugOptions.CGGlyphBorderColor = [UIColor colorWithRed:1.000 green:0.524 blue:0 已知问题 ============== -* YYText 并不能支持所有 CoreText/TextKit 的属性,比如 NSBackgroundColor、NSStrikethrough、NSUnderline、NSAttachment、NSLink 等,但 YYText 中基本都有对应属性作为替代。详情见上方表格。 +* YYText 并不能支持所有 CoreText/TextKit 的属性,比如 NSBackgroundColor、NSStrikethrough、NSUnderline、NSAttachment、~~NSLink~~ 等,但 YYText 中基本都有对应属性作为替代。详情见上方表格。 * YYTextView 未实现局部刷新,所以在输入和编辑大量的文本(比如超过大概五千个汉字、或大概一万个英文字符)时会出现较明显的卡顿现象。 * 竖排版时,添加 exclusionPaths 在少数情况下可能会导致文本显示空白。 * 当添加了非矩形的 textContainerPath,并且有嵌入大于文本排版方向宽度的 RunDelegate 时,RunDelegate 之后的文字会无法显示。这是 CoreText 的 Bug(或者说是 Feature)。 diff --git a/YYText/Component/YYTextLayout.m b/YYText/Component/YYTextLayout.m index 708ba1dd..f092c7ea 100644 --- a/YYText/Component/YYTextLayout.m +++ b/YYText/Component/YYTextLayout.m @@ -821,7 +821,7 @@ + (YYTextLayout *)layoutWithContainer:(YYTextContainer *)container text:(NSAttri layout.needDrawText = YES; void (^block)(NSDictionary *attrs, NSRange range, BOOL *stop) = ^(NSDictionary *attrs, NSRange range, BOOL *stop) { - if (attrs[YYTextHighlightAttributeName]) layout.containsHighlight = YES; + if (attrs[YYTextHighlightAttributeName] || attrs[NSLinkAttributeName]) layout.containsHighlight = YES; if (attrs[YYTextBlockBorderAttributeName]) layout.needDrawBlockBorder = YES; if (attrs[YYTextBackgroundBorderAttributeName]) layout.needDrawBackgroundBorder = YES; if (attrs[YYTextShadowAttributeName] || attrs[NSShadowAttributeName]) layout.needDrawShadow = YES; diff --git a/YYText/String/YYTextHighlight+NSLink.h b/YYText/String/YYTextHighlight+NSLink.h new file mode 100644 index 00000000..62452e6f --- /dev/null +++ b/YYText/String/YYTextHighlight+NSLink.h @@ -0,0 +1,19 @@ +// +// YYTextHighlight+NSLink.h +// YYTextDemo +// +// Created by Frank on 2021/4/8. +// Copyright © 2021 ibireme. All rights reserved. +// + +#import "YYTextAttribute.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface YYTextHighlight (NSLink) + +@property (nonatomic) NSURL *link; + +@end + +NS_ASSUME_NONNULL_END diff --git a/YYText/String/YYTextHighlight+NSLink.m b/YYText/String/YYTextHighlight+NSLink.m new file mode 100644 index 00000000..6603e39f --- /dev/null +++ b/YYText/String/YYTextHighlight+NSLink.m @@ -0,0 +1,23 @@ +// +// YYTextHighlight+NSLink.m +// YYTextDemo +// +// Created by Frank on 2021/4/8. +// Copyright © 2021 ibireme. All rights reserved. +// + +#import "YYTextHighlight+NSLink.h" + +@implementation YYTextHighlight (NSLink) + +- (NSURL *)link { + return self.userInfo[@"NSLink.URL"]; +} + +- (void)setLink:(NSURL *)link { + NSMutableDictionary *info = self.userInfo ? [self.userInfo mutableCopy] : [NSMutableDictionary new]; + info[@"NSLink.URL"] = link; + self.userInfo = info; +} + +@end diff --git a/YYText/YYText.h b/YYText/YYText.h index 0900d8b9..0789b8a3 100644 --- a/YYText/YYText.h +++ b/YYText/YYText.h @@ -30,6 +30,7 @@ FOUNDATION_EXPORT const unsigned char YYTextVersionString[]; #import #import #import +#import #else #import "YYLabel.h" #import "YYTextView.h" @@ -47,4 +48,5 @@ FOUNDATION_EXPORT const unsigned char YYTextVersionString[]; #import "NSAttributedString+YYText.h" #import "NSParagraphStyle+YYText.h" #import "UIPasteboard+YYText.h" +#import "YYText/YYTextHighlight+NSLink.h" #endif diff --git a/YYText/YYTextView.m b/YYText/YYTextView.m index 01b1629a..f50fa739 100644 --- a/YYText/YYTextView.m +++ b/YYText/YYTextView.m @@ -22,6 +22,7 @@ #import "NSAttributedString+YYText.h" #import "UIPasteboard+YYText.h" #import "UIView+YYText.h" +#import "YYTextHighlight+NSLink.h" static double _YYDeviceSystemVersion() { @@ -1150,7 +1151,17 @@ - (YYTextHighlight *)_getHighlightAtPoint:(CGPoint)point range:(NSRangePointer)r longestEffectiveRange:&highlightRange inRange:NSMakeRange(0, _innerText.length)]; - if (!highlight) return nil; + if (!highlight) { + // No highlight. So we check NSLink and create a highlight for NSLink + NSURL *link = [text attribute:NSLinkAttributeName + atIndex:startIndex + longestEffectiveRange:&highlightRange + inRange:NSMakeRange(0, _innerText.length)]; + if (!link) return nil; + + highlight = [YYTextHighlight new]; + highlight.link = link; + } BOOL shouldTap = YES, shouldLongPress = YES; if (!highlight.tapAction && !highlight.longPressAction) {