Note: Part of this attributed string is created"
72 | " by using basic HTML code, and some other attribues"
73 | " are set by code to demonstrate the usage of"
74 | " OHAttributedStringAdditions methods.
"
75 | "
Don't hesitate to try the search field at the top of the screen."
76 | " Searched text will be highlighted dynamically!
";
77 |
78 | NSMutableAttributedString* str = [NSMutableAttributedString attributedStringWithHTML:html];
79 |
80 | // Scale the font size by +50%
81 | [str enumerateFontsInRange:NSMakeRange(0,str.length)
82 | includeUndefined:YES
83 | usingBlock:^(UIFont *font, NSRange range, BOOL *stop)
84 | {
85 | if (!font) font = [NSAttributedString defaultFont];
86 | UIFont* newFont = [font fontWithSize:font.pointSize * 1.5f] ;
87 | [str setFont:newFont range:range];
88 | }];
89 |
90 | [str setTextUnderlined:YES range:[str.string rangeOfString:@"Amazing"]];
91 | NSRange listTitleRange = [str.string rangeOfString:LIST_TITLE];
92 | [str setTextColor:[UIColor colorWithRed:0 green:0.5 blue:0 alpha:1.] range:listTitleRange];
93 | [str setTextUnderlineStyle:NSUnderlineStyleThick|NSUnderlinePatternDot range:listTitleRange];
94 |
95 | [str changeParagraphStylesInRange:NSMakeRange(0, str.length)
96 | withBlock:^(NSMutableParagraphStyle* style, NSRange aRange)
97 | {
98 | // For example, justify only paragraphs that have a indentation
99 | if (style.firstLineHeadIndent > 0)
100 | {
101 | style.alignment = NSTextAlignmentJustified;
102 | }
103 | }];
104 |
105 | originalString = [str copy];
106 | });
107 | return originalString;
108 | }
109 |
110 | // MARK: Tap on a links
111 |
112 | // Links in TextView are already supported by UITextViewDelegate
113 | - (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange
114 | {
115 | // Intercept taps on links to display an alert instead of opening it in Safari
116 | [[[UIAlertView alloc] initWithTitle:@"URL Tapped"
117 | message:URL.absoluteString
118 | delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
119 | return NO;
120 | }
121 |
122 | // Links on UILabel have to use UITapGestureRecognizer (here added via the XIB)
123 | - (IBAction)tapOnFooter:(UITapGestureRecognizer *)tapGR
124 | {
125 | if (tapGR.state == UIGestureRecognizerStateEnded)
126 | {
127 | CGPoint tapPoint = [tapGR locationInView:self.footerLabel];
128 | NSUInteger pos = [self.footerLabel characterIndexAtPoint:tapPoint];
129 | if (pos != NSNotFound)
130 | {
131 | NSURL* urlTapped = [self.footerLabel.attributedText URLAtIndex:pos effectiveRange:NULL];
132 | if (urlTapped) [[UIApplication sharedApplication] openURL:urlTapped];
133 | }
134 | }
135 | }
136 |
137 |
138 | // MARK: Text Search
139 |
140 | - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
141 | {
142 | if (searchText.length > 0)
143 | {
144 | NSMutableAttributedString* highlightedString = [[self originalString] mutableCopy];
145 |
146 | NSRegularExpressionOptions options = NSRegularExpressionCaseInsensitive|NSRegularExpressionIgnoreMetacharacters;
147 | NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:searchText
148 | options:options
149 | error:NULL];
150 | [regex enumerateMatchesInString:self.textView.text
151 | options:0
152 | range:NSMakeRange(0, self.textView.text.length)
153 | usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop)
154 | {
155 | [highlightedString setTextBackgroundColor:[UIColor yellowColor] range:result.range];
156 | }];
157 |
158 | self.textView.attributedText = highlightedString;
159 | }
160 | else
161 | {
162 | // Reset to unhighlighted string
163 | self.textView.attributedText = [self originalString];
164 | }
165 | }
166 |
167 | - (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
168 | {
169 | [searchBar resignFirstResponder];
170 | }
171 |
172 | -(void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
173 | {
174 | self.textView.attributedText = [self originalString];
175 | [searchBar resignFirstResponder];
176 | }
177 |
178 | - (void)keyboardAnimation:(NSNotification*)notif
179 | {
180 | NSTimeInterval animDuration = [notif.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
181 | CGRect endFrame = [notif.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
182 |
183 | self.bottomDistance.constant = self.view.window.bounds.size.height - endFrame.origin.y;
184 | [UIView animateWithDuration:animDuration animations:^{
185 | [self.textView layoutIfNeeded];
186 | }];
187 | }
188 |
189 | @end
190 |
--------------------------------------------------------------------------------
/Example/AttributedStringDemo/ASDViewController.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda.
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/Example/AttributedStringDemo/AttributedStringDemo-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | ${PRODUCT_NAME}
9 | CFBundleExecutable
10 | ${EXECUTABLE_NAME}
11 | CFBundleIdentifier
12 | com.alisoftware.${PRODUCT_NAME:rfc1034identifier}
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | ${PRODUCT_NAME}
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1.0
25 | LSRequiresIPhoneOS
26 |
27 | NSMainNibFile
28 | ASDViewController
29 | UILaunchStoryboardName
30 | ASDViewController
31 | UIRequiredDeviceCapabilities
32 |
33 | armv7
34 |
35 | UISupportedInterfaceOrientations
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationLandscapeLeft
39 | UIInterfaceOrientationLandscapeRight
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/Example/AttributedStringDemo/AttributedStringDemo-Prefix.pch:
--------------------------------------------------------------------------------
1 | //
2 | // Prefix header
3 | //
4 | // The contents of this file are implicitly included at the beginning of every source file.
5 | //
6 |
7 | #import
8 |
9 | #ifndef __IPHONE_5_0
10 | #warning "This project uses features only available in iOS SDK 5.0 and later."
11 | #endif
12 |
13 | #ifdef __OBJC__
14 | #import
15 | #import
16 | #endif
17 |
--------------------------------------------------------------------------------
/Example/AttributedStringDemo/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "40x40",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "60x60",
16 | "scale" : "2x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/Example/AttributedStringDemo/Images.xcassets/LaunchImage.launchimage/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "orientation" : "portrait",
5 | "idiom" : "iphone",
6 | "extent" : "full-screen",
7 | "minimum-system-version" : "7.0",
8 | "scale" : "2x"
9 | },
10 | {
11 | "orientation" : "portrait",
12 | "idiom" : "iphone",
13 | "subtype" : "retina4",
14 | "extent" : "full-screen",
15 | "minimum-system-version" : "7.0",
16 | "scale" : "2x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/Example/AttributedStringDemo/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // AttributedStringDemo
4 | //
5 | // Created by Olivier Halligon on 13/08/2014.
6 | // Copyright (c) 2014 AliSoftware. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "ASDAppDelegate.h"
12 |
13 | int main(int argc, char * argv[])
14 | {
15 | @autoreleasepool {
16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([ASDAppDelegate class]));
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Example/Podfile:
--------------------------------------------------------------------------------
1 | xcodeproj 'AttributedStringDemo.xcodeproj'
2 | platform :ios, "7.0"
3 |
4 | link_with 'AttributedStringDemo', 'UnitTests'
5 | pod 'OHAttributedStringAdditions', :path => '..'
6 |
--------------------------------------------------------------------------------
/Example/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - OHAttributedStringAdditions (1.3.0):
3 | - OHAttributedStringAdditions/Base (= 1.3.0)
4 | - OHAttributedStringAdditions/UILabel (= 1.3.0)
5 | - OHAttributedStringAdditions/Base (1.3.0)
6 | - OHAttributedStringAdditions/UILabel (1.3.0):
7 | - OHAttributedStringAdditions/Base
8 |
9 | DEPENDENCIES:
10 | - OHAttributedStringAdditions (from `..`)
11 |
12 | EXTERNAL SOURCES:
13 | OHAttributedStringAdditions:
14 | :path: ..
15 |
16 | SPEC CHECKSUMS:
17 | OHAttributedStringAdditions: d810cff43f5dd0054df62de2e7bf472c9a2b9d3e
18 |
19 | COCOAPODS: 0.36.0
20 |
--------------------------------------------------------------------------------
/Example/Pods/Headers/Private/OHAttributedStringAdditions/NSAttributedString+OHAdditions.h:
--------------------------------------------------------------------------------
1 | ../../../../../Source/NSAttributedString+OHAdditions.h
--------------------------------------------------------------------------------
/Example/Pods/Headers/Private/OHAttributedStringAdditions/NSMutableAttributedString+OHAdditions.h:
--------------------------------------------------------------------------------
1 | ../../../../../Source/NSMutableAttributedString+OHAdditions.h
--------------------------------------------------------------------------------
/Example/Pods/Headers/Private/OHAttributedStringAdditions/OHAttributedStringAdditions.h:
--------------------------------------------------------------------------------
1 | ../../../../../Source/OHAttributedStringAdditions.h
--------------------------------------------------------------------------------
/Example/Pods/Headers/Private/OHAttributedStringAdditions/UIFont+OHAdditions.h:
--------------------------------------------------------------------------------
1 | ../../../../../Source/UIFont+OHAdditions.h
--------------------------------------------------------------------------------
/Example/Pods/Headers/Private/OHAttributedStringAdditions/UILabel+OHAdditions.h:
--------------------------------------------------------------------------------
1 | ../../../../../Source/UILabel+OHAdditions.h
--------------------------------------------------------------------------------
/Example/Pods/Headers/Public/OHAttributedStringAdditions/NSAttributedString+OHAdditions.h:
--------------------------------------------------------------------------------
1 | ../../../../../Source/NSAttributedString+OHAdditions.h
--------------------------------------------------------------------------------
/Example/Pods/Headers/Public/OHAttributedStringAdditions/NSMutableAttributedString+OHAdditions.h:
--------------------------------------------------------------------------------
1 | ../../../../../Source/NSMutableAttributedString+OHAdditions.h
--------------------------------------------------------------------------------
/Example/Pods/Headers/Public/OHAttributedStringAdditions/OHAttributedStringAdditions.h:
--------------------------------------------------------------------------------
1 | ../../../../../Source/OHAttributedStringAdditions.h
--------------------------------------------------------------------------------
/Example/Pods/Headers/Public/OHAttributedStringAdditions/UIFont+OHAdditions.h:
--------------------------------------------------------------------------------
1 | ../../../../../Source/UIFont+OHAdditions.h
--------------------------------------------------------------------------------
/Example/Pods/Headers/Public/OHAttributedStringAdditions/UILabel+OHAdditions.h:
--------------------------------------------------------------------------------
1 | ../../../../../Source/UILabel+OHAdditions.h
--------------------------------------------------------------------------------
/Example/Pods/Local Podspecs/OHAttributedStringAdditions.podspec.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "OHAttributedStringAdditions",
3 | "version": "1.3.0",
4 | "summary": "Categories on NSAttributedString to add a lot of very useful convenience methods.",
5 | "description": "This pod contains categories on `NSAttributedString` to add a lot of very useful\nconvenience methods to manipulate attributed strings.\n\nThe includes convenience methods to:\n * set attributes on a given range\n * get attributes at a given index\n\nConvenience methods are available for a lot of common attributes, including:\n * Fonts\n * Text Foreground and Background Colors\n * Text Style (bold, italics, underline)\n * Links (URLs)\n * Baseline offset, subscript, superscript\n * Text alignment, linebreak mode, character spacing\n * Paragraph Style (text indent, linespacing, …)\n * etc.\n",
6 | "homepage": "https://github.com/AliSoftware/OHAttributedStringAdditions",
7 | "license": {
8 | "type": "MIT",
9 | "file": "LICENSE"
10 | },
11 | "authors": {
12 | "Olivier Halligon": "olivier@halligon.net"
13 | },
14 | "social_media_url": "http://twitter.com/aligatr",
15 | "platforms": {
16 | "ios": "7.0"
17 | },
18 | "source": {
19 | "git": "https://github.com/AliSoftware/OHAttributedStringAdditions.git",
20 | "tag": "1.3.0"
21 | },
22 | "requires_arc": true,
23 | "subspecs": [
24 | {
25 | "name": "Base",
26 | "source_files": [
27 | "Source/OHAttributedStringAdditions.h",
28 | "Source/{NSAttributedString,NSMutableAttributedString,UIFont}+OHAdditions.{h,m}"
29 | ]
30 | },
31 | {
32 | "name": "UILabel",
33 | "source_files": "Source/UILabel+OHAdditions.{h,m}",
34 | "dependencies": {
35 | "OHAttributedStringAdditions/Base": [
36 |
37 | ]
38 | }
39 | }
40 | ]
41 | }
42 |
--------------------------------------------------------------------------------
/Example/Pods/Manifest.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - OHAttributedStringAdditions (1.3.0):
3 | - OHAttributedStringAdditions/Base (= 1.3.0)
4 | - OHAttributedStringAdditions/UILabel (= 1.3.0)
5 | - OHAttributedStringAdditions/Base (1.3.0)
6 | - OHAttributedStringAdditions/UILabel (1.3.0):
7 | - OHAttributedStringAdditions/Base
8 |
9 | DEPENDENCIES:
10 | - OHAttributedStringAdditions (from `..`)
11 |
12 | EXTERNAL SOURCES:
13 | OHAttributedStringAdditions:
14 | :path: ..
15 |
16 | SPEC CHECKSUMS:
17 | OHAttributedStringAdditions: d810cff43f5dd0054df62de2e7bf472c9a2b9d3e
18 |
19 | COCOAPODS: 0.36.0
20 |
--------------------------------------------------------------------------------
/Example/Pods/Pods.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 0605D8499077ACA2174A7BC3 /* NSMutableAttributedString+OHAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = CAE2BB42DD950560D765A81C /* NSMutableAttributedString+OHAdditions.h */; };
11 | 1B4AEE2C2A1A4CAE737DBAFA /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1B64F5E8869E93D36A083D0E /* Foundation.framework */; };
12 | 2124593D4871E36469596BA1 /* NSAttributedString+OHAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 5926D17671A01394ED1BBDEF /* NSAttributedString+OHAdditions.h */; };
13 | 231C2348E53AFD20361397A7 /* OHAttributedStringAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 4186D2534B060149A6E235C1 /* OHAttributedStringAdditions.h */; };
14 | 25EFA894FCAB729EB31F5606 /* UIFont+OHAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 6EC90CB963E963CD21530F7B /* UIFont+OHAdditions.h */; };
15 | 30F87631880DD8EFACC34667 /* NSMutableAttributedString+OHAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = BE230D04B38FD2AEB0852FDE /* NSMutableAttributedString+OHAdditions.m */; };
16 | 354E4173B24BB8DE3237DDB1 /* Pods-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 8769CEF18EA4239A15E17E08 /* Pods-dummy.m */; };
17 | 37FCBABCC1038ED244ECCDEC /* Pods-OHAttributedStringAdditions-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = C930613009EE836D78C77947 /* Pods-OHAttributedStringAdditions-dummy.m */; };
18 | 519F0CDD757677CDBCFAF7F4 /* NSAttributedString+OHAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 500F90DAE1944C652DBF5B29 /* NSAttributedString+OHAdditions.m */; };
19 | 64F7F009BD63D01059EB99F3 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1B64F5E8869E93D36A083D0E /* Foundation.framework */; };
20 | 8EA0B859EFB055F84A3E1ED4 /* UILabel+OHAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 984EAF4CC7D0629D23B498A5 /* UILabel+OHAdditions.h */; };
21 | 9AF427D6131DC57D3721268D /* UIFont+OHAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = A268CD3735944768CBB101FB /* UIFont+OHAdditions.m */; };
22 | B9E9D0C465FB21FAB7024D1C /* UILabel+OHAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = A52AEDC08C1CEC5F1CCF1AFE /* UILabel+OHAdditions.m */; };
23 | /* End PBXBuildFile section */
24 |
25 | /* Begin PBXContainerItemProxy section */
26 | E039D9E7A242C7F396BE9B4E /* PBXContainerItemProxy */ = {
27 | isa = PBXContainerItemProxy;
28 | containerPortal = 8B9C3D0F71044B5FD372CFAB /* Project object */;
29 | proxyType = 1;
30 | remoteGlobalIDString = B630051DB34C05310D5E7AEA;
31 | remoteInfo = "Pods-OHAttributedStringAdditions";
32 | };
33 | /* End PBXContainerItemProxy section */
34 |
35 | /* Begin PBXFileReference section */
36 | 1B64F5E8869E93D36A083D0E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.1.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; };
37 | 4186D2534B060149A6E235C1 /* OHAttributedStringAdditions.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = OHAttributedStringAdditions.h; sourceTree = ""; };
38 | 48EE5962938B9266F611F7E6 /* Pods-resources.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-resources.sh"; sourceTree = ""; };
39 | 500F90DAE1944C652DBF5B29 /* NSAttributedString+OHAdditions.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "NSAttributedString+OHAdditions.m"; sourceTree = ""; };
40 | 5926D17671A01394ED1BBDEF /* NSAttributedString+OHAdditions.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "NSAttributedString+OHAdditions.h"; sourceTree = ""; };
41 | 69C21083782E5B9B65BCAED6 /* Pods-OHAttributedStringAdditions-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-OHAttributedStringAdditions-prefix.pch"; sourceTree = ""; };
42 | 6EC90CB963E963CD21530F7B /* UIFont+OHAdditions.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "UIFont+OHAdditions.h"; sourceTree = ""; };
43 | 8769CEF18EA4239A15E17E08 /* Pods-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-dummy.m"; sourceTree = ""; };
44 | 8DDCD4DB15F67A9A237E9D6C /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Pods.release.xcconfig; sourceTree = ""; };
45 | 90BEBAE820C26D9422299265 /* Pods-OHAttributedStringAdditions-Private.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-OHAttributedStringAdditions-Private.xcconfig"; sourceTree = ""; };
46 | 984EAF4CC7D0629D23B498A5 /* UILabel+OHAdditions.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "UILabel+OHAdditions.h"; sourceTree = ""; };
47 | A268CD3735944768CBB101FB /* UIFont+OHAdditions.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "UIFont+OHAdditions.m"; sourceTree = ""; };
48 | A52AEDC08C1CEC5F1CCF1AFE /* UILabel+OHAdditions.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "UILabel+OHAdditions.m"; sourceTree = ""; };
49 | B0C3B97392A6644944FBC06F /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; };
50 | B67CCA968229B78C358ECAF5 /* Pods-OHAttributedStringAdditions.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-OHAttributedStringAdditions.xcconfig"; sourceTree = ""; };
51 | BE230D04B38FD2AEB0852FDE /* NSMutableAttributedString+OHAdditions.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "NSMutableAttributedString+OHAdditions.m"; sourceTree = ""; };
52 | C1CEAD0CF45B09A94354B503 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Pods.debug.xcconfig; sourceTree = ""; };
53 | C930613009EE836D78C77947 /* Pods-OHAttributedStringAdditions-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-OHAttributedStringAdditions-dummy.m"; sourceTree = ""; };
54 | CAE2BB42DD950560D765A81C /* NSMutableAttributedString+OHAdditions.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "NSMutableAttributedString+OHAdditions.h"; sourceTree = ""; };
55 | CE8C8E1A2D126907A81925FD /* Pods-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-acknowledgements.markdown"; sourceTree = ""; };
56 | D837E030FA87A9157429DC40 /* libPods-OHAttributedStringAdditions.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-OHAttributedStringAdditions.a"; sourceTree = BUILT_PRODUCTS_DIR; };
57 | D9F11F1515FA68B221E180CB /* Podfile */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
58 | E3981D374D44583DA685DE7B /* Pods-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-acknowledgements.plist"; sourceTree = ""; };
59 | F2227E27B1387F758A38E3A6 /* Pods-environment.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-environment.h"; sourceTree = ""; };
60 | /* End PBXFileReference section */
61 |
62 | /* Begin PBXFrameworksBuildPhase section */
63 | 83177EA619BC14F68D90BC0A /* Frameworks */ = {
64 | isa = PBXFrameworksBuildPhase;
65 | buildActionMask = 2147483647;
66 | files = (
67 | 64F7F009BD63D01059EB99F3 /* Foundation.framework in Frameworks */,
68 | );
69 | runOnlyForDeploymentPostprocessing = 0;
70 | };
71 | 974BBBE722E6CF70FEDE20AD /* Frameworks */ = {
72 | isa = PBXFrameworksBuildPhase;
73 | buildActionMask = 2147483647;
74 | files = (
75 | 1B4AEE2C2A1A4CAE737DBAFA /* Foundation.framework in Frameworks */,
76 | );
77 | runOnlyForDeploymentPostprocessing = 0;
78 | };
79 | /* End PBXFrameworksBuildPhase section */
80 |
81 | /* Begin PBXGroup section */
82 | 0CBA8EB78432B224049F986A /* OHAttributedStringAdditions */ = {
83 | isa = PBXGroup;
84 | children = (
85 | 34A465BC0C3AE4109BB07F33 /* Base */,
86 | ED36A7090A51CA798CCD4990 /* Support Files */,
87 | 2B97902AF5C8F44A5B320BDD /* UILabel */,
88 | );
89 | name = OHAttributedStringAdditions;
90 | path = ../..;
91 | sourceTree = "";
92 | };
93 | 1E67CAD93DDAA1D312FFD665 = {
94 | isa = PBXGroup;
95 | children = (
96 | D9F11F1515FA68B221E180CB /* Podfile */,
97 | FA6326C49294BEFD58E993AF /* Development Pods */,
98 | 52C42E6C413F10D6BA2820B1 /* Frameworks */,
99 | 4A839CB6C06DB50EA78AF0C6 /* Products */,
100 | 4D875F4D1B68663E567D9A14 /* Targets Support Files */,
101 | );
102 | sourceTree = "";
103 | };
104 | 2B97902AF5C8F44A5B320BDD /* UILabel */ = {
105 | isa = PBXGroup;
106 | children = (
107 | 89524B7AA4A0D67BB6444CF1 /* Source */,
108 | );
109 | name = UILabel;
110 | sourceTree = "";
111 | };
112 | 34A465BC0C3AE4109BB07F33 /* Base */ = {
113 | isa = PBXGroup;
114 | children = (
115 | 99FB352DFC77C8A768656F34 /* Source */,
116 | );
117 | name = Base;
118 | sourceTree = "";
119 | };
120 | 4A839CB6C06DB50EA78AF0C6 /* Products */ = {
121 | isa = PBXGroup;
122 | children = (
123 | B0C3B97392A6644944FBC06F /* libPods.a */,
124 | D837E030FA87A9157429DC40 /* libPods-OHAttributedStringAdditions.a */,
125 | );
126 | name = Products;
127 | sourceTree = "";
128 | };
129 | 4D875F4D1B68663E567D9A14 /* Targets Support Files */ = {
130 | isa = PBXGroup;
131 | children = (
132 | 64E6C286A732C288BDF109DD /* Pods */,
133 | );
134 | name = "Targets Support Files";
135 | sourceTree = "";
136 | };
137 | 52C42E6C413F10D6BA2820B1 /* Frameworks */ = {
138 | isa = PBXGroup;
139 | children = (
140 | 93DAF13F571CBB90564B5564 /* iOS */,
141 | );
142 | name = Frameworks;
143 | sourceTree = "";
144 | };
145 | 64E6C286A732C288BDF109DD /* Pods */ = {
146 | isa = PBXGroup;
147 | children = (
148 | CE8C8E1A2D126907A81925FD /* Pods-acknowledgements.markdown */,
149 | E3981D374D44583DA685DE7B /* Pods-acknowledgements.plist */,
150 | 8769CEF18EA4239A15E17E08 /* Pods-dummy.m */,
151 | F2227E27B1387F758A38E3A6 /* Pods-environment.h */,
152 | 48EE5962938B9266F611F7E6 /* Pods-resources.sh */,
153 | C1CEAD0CF45B09A94354B503 /* Pods.debug.xcconfig */,
154 | 8DDCD4DB15F67A9A237E9D6C /* Pods.release.xcconfig */,
155 | );
156 | name = Pods;
157 | path = "Target Support Files/Pods";
158 | sourceTree = "";
159 | };
160 | 89524B7AA4A0D67BB6444CF1 /* Source */ = {
161 | isa = PBXGroup;
162 | children = (
163 | 984EAF4CC7D0629D23B498A5 /* UILabel+OHAdditions.h */,
164 | A52AEDC08C1CEC5F1CCF1AFE /* UILabel+OHAdditions.m */,
165 | );
166 | path = Source;
167 | sourceTree = "";
168 | };
169 | 93DAF13F571CBB90564B5564 /* iOS */ = {
170 | isa = PBXGroup;
171 | children = (
172 | 1B64F5E8869E93D36A083D0E /* Foundation.framework */,
173 | );
174 | name = iOS;
175 | sourceTree = "";
176 | };
177 | 99FB352DFC77C8A768656F34 /* Source */ = {
178 | isa = PBXGroup;
179 | children = (
180 | 5926D17671A01394ED1BBDEF /* NSAttributedString+OHAdditions.h */,
181 | 500F90DAE1944C652DBF5B29 /* NSAttributedString+OHAdditions.m */,
182 | CAE2BB42DD950560D765A81C /* NSMutableAttributedString+OHAdditions.h */,
183 | BE230D04B38FD2AEB0852FDE /* NSMutableAttributedString+OHAdditions.m */,
184 | 4186D2534B060149A6E235C1 /* OHAttributedStringAdditions.h */,
185 | 6EC90CB963E963CD21530F7B /* UIFont+OHAdditions.h */,
186 | A268CD3735944768CBB101FB /* UIFont+OHAdditions.m */,
187 | );
188 | path = Source;
189 | sourceTree = "";
190 | };
191 | ED36A7090A51CA798CCD4990 /* Support Files */ = {
192 | isa = PBXGroup;
193 | children = (
194 | B67CCA968229B78C358ECAF5 /* Pods-OHAttributedStringAdditions.xcconfig */,
195 | 90BEBAE820C26D9422299265 /* Pods-OHAttributedStringAdditions-Private.xcconfig */,
196 | C930613009EE836D78C77947 /* Pods-OHAttributedStringAdditions-dummy.m */,
197 | 69C21083782E5B9B65BCAED6 /* Pods-OHAttributedStringAdditions-prefix.pch */,
198 | );
199 | name = "Support Files";
200 | path = "Example/Pods/Target Support Files/Pods-OHAttributedStringAdditions";
201 | sourceTree = "";
202 | };
203 | FA6326C49294BEFD58E993AF /* Development Pods */ = {
204 | isa = PBXGroup;
205 | children = (
206 | 0CBA8EB78432B224049F986A /* OHAttributedStringAdditions */,
207 | );
208 | name = "Development Pods";
209 | sourceTree = "";
210 | };
211 | /* End PBXGroup section */
212 |
213 | /* Begin PBXHeadersBuildPhase section */
214 | 291E79D89293D48C7967619C /* Headers */ = {
215 | isa = PBXHeadersBuildPhase;
216 | buildActionMask = 2147483647;
217 | files = (
218 | 2124593D4871E36469596BA1 /* NSAttributedString+OHAdditions.h in Headers */,
219 | 0605D8499077ACA2174A7BC3 /* NSMutableAttributedString+OHAdditions.h in Headers */,
220 | 231C2348E53AFD20361397A7 /* OHAttributedStringAdditions.h in Headers */,
221 | 25EFA894FCAB729EB31F5606 /* UIFont+OHAdditions.h in Headers */,
222 | 8EA0B859EFB055F84A3E1ED4 /* UILabel+OHAdditions.h in Headers */,
223 | );
224 | runOnlyForDeploymentPostprocessing = 0;
225 | };
226 | /* End PBXHeadersBuildPhase section */
227 |
228 | /* Begin PBXNativeTarget section */
229 | 584F80B49FDB8CDD09B4C721 /* Pods */ = {
230 | isa = PBXNativeTarget;
231 | buildConfigurationList = AAC84FAA32524CC52E1136C5 /* Build configuration list for PBXNativeTarget "Pods" */;
232 | buildPhases = (
233 | 06F09373BEDA145C566C772C /* Sources */,
234 | 974BBBE722E6CF70FEDE20AD /* Frameworks */,
235 | );
236 | buildRules = (
237 | );
238 | dependencies = (
239 | DF5CFFB55714D0980D9BA767 /* PBXTargetDependency */,
240 | );
241 | name = Pods;
242 | productName = Pods;
243 | productReference = B0C3B97392A6644944FBC06F /* libPods.a */;
244 | productType = "com.apple.product-type.library.static";
245 | };
246 | B630051DB34C05310D5E7AEA /* Pods-OHAttributedStringAdditions */ = {
247 | isa = PBXNativeTarget;
248 | buildConfigurationList = 0AF7F5B14D08DEEAB0282CAA /* Build configuration list for PBXNativeTarget "Pods-OHAttributedStringAdditions" */;
249 | buildPhases = (
250 | 381385E9228E3AFBA7A4CD44 /* Sources */,
251 | 83177EA619BC14F68D90BC0A /* Frameworks */,
252 | 291E79D89293D48C7967619C /* Headers */,
253 | );
254 | buildRules = (
255 | );
256 | dependencies = (
257 | );
258 | name = "Pods-OHAttributedStringAdditions";
259 | productName = "Pods-OHAttributedStringAdditions";
260 | productReference = D837E030FA87A9157429DC40 /* libPods-OHAttributedStringAdditions.a */;
261 | productType = "com.apple.product-type.library.static";
262 | };
263 | /* End PBXNativeTarget section */
264 |
265 | /* Begin PBXProject section */
266 | 8B9C3D0F71044B5FD372CFAB /* Project object */ = {
267 | isa = PBXProject;
268 | attributes = {
269 | LastUpgradeCheck = 0510;
270 | };
271 | buildConfigurationList = B6ECAD8F91C0E56D54A5F0D0 /* Build configuration list for PBXProject "Pods" */;
272 | compatibilityVersion = "Xcode 3.2";
273 | developmentRegion = English;
274 | hasScannedForEncodings = 0;
275 | knownRegions = (
276 | en,
277 | );
278 | mainGroup = 1E67CAD93DDAA1D312FFD665;
279 | productRefGroup = 4A839CB6C06DB50EA78AF0C6 /* Products */;
280 | projectDirPath = "";
281 | projectRoot = "";
282 | targets = (
283 | 584F80B49FDB8CDD09B4C721 /* Pods */,
284 | B630051DB34C05310D5E7AEA /* Pods-OHAttributedStringAdditions */,
285 | );
286 | };
287 | /* End PBXProject section */
288 |
289 | /* Begin PBXSourcesBuildPhase section */
290 | 06F09373BEDA145C566C772C /* Sources */ = {
291 | isa = PBXSourcesBuildPhase;
292 | buildActionMask = 2147483647;
293 | files = (
294 | 354E4173B24BB8DE3237DDB1 /* Pods-dummy.m in Sources */,
295 | );
296 | runOnlyForDeploymentPostprocessing = 0;
297 | };
298 | 381385E9228E3AFBA7A4CD44 /* Sources */ = {
299 | isa = PBXSourcesBuildPhase;
300 | buildActionMask = 2147483647;
301 | files = (
302 | 519F0CDD757677CDBCFAF7F4 /* NSAttributedString+OHAdditions.m in Sources */,
303 | 30F87631880DD8EFACC34667 /* NSMutableAttributedString+OHAdditions.m in Sources */,
304 | 37FCBABCC1038ED244ECCDEC /* Pods-OHAttributedStringAdditions-dummy.m in Sources */,
305 | 9AF427D6131DC57D3721268D /* UIFont+OHAdditions.m in Sources */,
306 | B9E9D0C465FB21FAB7024D1C /* UILabel+OHAdditions.m in Sources */,
307 | );
308 | runOnlyForDeploymentPostprocessing = 0;
309 | };
310 | /* End PBXSourcesBuildPhase section */
311 |
312 | /* Begin PBXTargetDependency section */
313 | DF5CFFB55714D0980D9BA767 /* PBXTargetDependency */ = {
314 | isa = PBXTargetDependency;
315 | name = "Pods-OHAttributedStringAdditions";
316 | target = B630051DB34C05310D5E7AEA /* Pods-OHAttributedStringAdditions */;
317 | targetProxy = E039D9E7A242C7F396BE9B4E /* PBXContainerItemProxy */;
318 | };
319 | /* End PBXTargetDependency section */
320 |
321 | /* Begin XCBuildConfiguration section */
322 | 22F095CD0312C2692A9EAD47 /* Debug */ = {
323 | isa = XCBuildConfiguration;
324 | baseConfigurationReference = C1CEAD0CF45B09A94354B503 /* Pods.debug.xcconfig */;
325 | buildSettings = {
326 | ENABLE_STRICT_OBJC_MSGSEND = YES;
327 | IPHONEOS_DEPLOYMENT_TARGET = 7.0;
328 | MTL_ENABLE_DEBUG_INFO = YES;
329 | OTHER_LDFLAGS = "";
330 | OTHER_LIBTOOLFLAGS = "";
331 | PODS_ROOT = "$(SRCROOT)";
332 | PRODUCT_NAME = "$(TARGET_NAME)";
333 | SDKROOT = iphoneos;
334 | SKIP_INSTALL = YES;
335 | };
336 | name = Debug;
337 | };
338 | 2DD2249116856B6B7491B3EE /* Debug */ = {
339 | isa = XCBuildConfiguration;
340 | buildSettings = {
341 | ALWAYS_SEARCH_USER_PATHS = NO;
342 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
343 | CLANG_CXX_LIBRARY = "libc++";
344 | CLANG_ENABLE_MODULES = YES;
345 | CLANG_ENABLE_OBJC_ARC = YES;
346 | CLANG_WARN_BOOL_CONVERSION = YES;
347 | CLANG_WARN_CONSTANT_CONVERSION = YES;
348 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES;
349 | CLANG_WARN_EMPTY_BODY = YES;
350 | CLANG_WARN_ENUM_CONVERSION = YES;
351 | CLANG_WARN_INT_CONVERSION = YES;
352 | CLANG_WARN_OBJC_ROOT_CLASS = YES;
353 | CLANG_WARN_UNREACHABLE_CODE = YES;
354 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
355 | COPY_PHASE_STRIP = NO;
356 | GCC_C_LANGUAGE_STANDARD = gnu99;
357 | GCC_DYNAMIC_NO_PIC = NO;
358 | GCC_OPTIMIZATION_LEVEL = 0;
359 | GCC_PREPROCESSOR_DEFINITIONS = (
360 | "DEBUG=1",
361 | "$(inherited)",
362 | );
363 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
364 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
365 | GCC_WARN_ABOUT_RETURN_TYPE = YES;
366 | GCC_WARN_UNDECLARED_SELECTOR = YES;
367 | GCC_WARN_UNINITIALIZED_AUTOS = YES;
368 | GCC_WARN_UNUSED_FUNCTION = YES;
369 | GCC_WARN_UNUSED_VARIABLE = YES;
370 | IPHONEOS_DEPLOYMENT_TARGET = 7.0;
371 | ONLY_ACTIVE_ARCH = YES;
372 | STRIP_INSTALLED_PRODUCT = NO;
373 | SYMROOT = "${SRCROOT}/../build";
374 | };
375 | name = Debug;
376 | };
377 | 4A7C2B5B472F220B86DB087A /* Release */ = {
378 | isa = XCBuildConfiguration;
379 | baseConfigurationReference = 8DDCD4DB15F67A9A237E9D6C /* Pods.release.xcconfig */;
380 | buildSettings = {
381 | ENABLE_STRICT_OBJC_MSGSEND = YES;
382 | IPHONEOS_DEPLOYMENT_TARGET = 7.0;
383 | MTL_ENABLE_DEBUG_INFO = NO;
384 | OTHER_LDFLAGS = "";
385 | OTHER_LIBTOOLFLAGS = "";
386 | PODS_ROOT = "$(SRCROOT)";
387 | PRODUCT_NAME = "$(TARGET_NAME)";
388 | SDKROOT = iphoneos;
389 | SKIP_INSTALL = YES;
390 | };
391 | name = Release;
392 | };
393 | 53238B73FE93D074B2FC82F6 /* Debug */ = {
394 | isa = XCBuildConfiguration;
395 | baseConfigurationReference = 90BEBAE820C26D9422299265 /* Pods-OHAttributedStringAdditions-Private.xcconfig */;
396 | buildSettings = {
397 | ENABLE_STRICT_OBJC_MSGSEND = YES;
398 | GCC_PREFIX_HEADER = "Target Support Files/Pods-OHAttributedStringAdditions/Pods-OHAttributedStringAdditions-prefix.pch";
399 | IPHONEOS_DEPLOYMENT_TARGET = 7.0;
400 | MTL_ENABLE_DEBUG_INFO = YES;
401 | OTHER_LDFLAGS = "";
402 | OTHER_LIBTOOLFLAGS = "";
403 | PRODUCT_NAME = "$(TARGET_NAME)";
404 | SDKROOT = iphoneos;
405 | SKIP_INSTALL = YES;
406 | };
407 | name = Debug;
408 | };
409 | 900296E669CAF66ED53C128F /* Release */ = {
410 | isa = XCBuildConfiguration;
411 | baseConfigurationReference = 90BEBAE820C26D9422299265 /* Pods-OHAttributedStringAdditions-Private.xcconfig */;
412 | buildSettings = {
413 | ENABLE_STRICT_OBJC_MSGSEND = YES;
414 | GCC_PREFIX_HEADER = "Target Support Files/Pods-OHAttributedStringAdditions/Pods-OHAttributedStringAdditions-prefix.pch";
415 | IPHONEOS_DEPLOYMENT_TARGET = 7.0;
416 | MTL_ENABLE_DEBUG_INFO = NO;
417 | OTHER_LDFLAGS = "";
418 | OTHER_LIBTOOLFLAGS = "";
419 | PRODUCT_NAME = "$(TARGET_NAME)";
420 | SDKROOT = iphoneos;
421 | SKIP_INSTALL = YES;
422 | };
423 | name = Release;
424 | };
425 | 9BA434F293314F021DBF2A4B /* Release */ = {
426 | isa = XCBuildConfiguration;
427 | buildSettings = {
428 | ALWAYS_SEARCH_USER_PATHS = NO;
429 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
430 | CLANG_CXX_LIBRARY = "libc++";
431 | CLANG_ENABLE_MODULES = YES;
432 | CLANG_ENABLE_OBJC_ARC = YES;
433 | CLANG_WARN_BOOL_CONVERSION = YES;
434 | CLANG_WARN_CONSTANT_CONVERSION = YES;
435 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES;
436 | CLANG_WARN_EMPTY_BODY = YES;
437 | CLANG_WARN_ENUM_CONVERSION = YES;
438 | CLANG_WARN_INT_CONVERSION = YES;
439 | CLANG_WARN_OBJC_ROOT_CLASS = YES;
440 | CLANG_WARN_UNREACHABLE_CODE = YES;
441 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
442 | COPY_PHASE_STRIP = YES;
443 | ENABLE_NS_ASSERTIONS = NO;
444 | GCC_C_LANGUAGE_STANDARD = gnu99;
445 | GCC_PREPROCESSOR_DEFINITIONS = "RELEASE=1";
446 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
447 | GCC_WARN_ABOUT_RETURN_TYPE = YES;
448 | GCC_WARN_UNDECLARED_SELECTOR = YES;
449 | GCC_WARN_UNINITIALIZED_AUTOS = YES;
450 | GCC_WARN_UNUSED_FUNCTION = YES;
451 | GCC_WARN_UNUSED_VARIABLE = YES;
452 | IPHONEOS_DEPLOYMENT_TARGET = 7.0;
453 | STRIP_INSTALLED_PRODUCT = NO;
454 | SYMROOT = "${SRCROOT}/../build";
455 | VALIDATE_PRODUCT = YES;
456 | };
457 | name = Release;
458 | };
459 | /* End XCBuildConfiguration section */
460 |
461 | /* Begin XCConfigurationList section */
462 | 0AF7F5B14D08DEEAB0282CAA /* Build configuration list for PBXNativeTarget "Pods-OHAttributedStringAdditions" */ = {
463 | isa = XCConfigurationList;
464 | buildConfigurations = (
465 | 53238B73FE93D074B2FC82F6 /* Debug */,
466 | 900296E669CAF66ED53C128F /* Release */,
467 | );
468 | defaultConfigurationIsVisible = 0;
469 | defaultConfigurationName = Release;
470 | };
471 | AAC84FAA32524CC52E1136C5 /* Build configuration list for PBXNativeTarget "Pods" */ = {
472 | isa = XCConfigurationList;
473 | buildConfigurations = (
474 | 22F095CD0312C2692A9EAD47 /* Debug */,
475 | 4A7C2B5B472F220B86DB087A /* Release */,
476 | );
477 | defaultConfigurationIsVisible = 0;
478 | defaultConfigurationName = Release;
479 | };
480 | B6ECAD8F91C0E56D54A5F0D0 /* Build configuration list for PBXProject "Pods" */ = {
481 | isa = XCConfigurationList;
482 | buildConfigurations = (
483 | 2DD2249116856B6B7491B3EE /* Debug */,
484 | 9BA434F293314F021DBF2A4B /* Release */,
485 | );
486 | defaultConfigurationIsVisible = 0;
487 | defaultConfigurationName = Release;
488 | };
489 | /* End XCConfigurationList section */
490 | };
491 | rootObject = 8B9C3D0F71044B5FD372CFAB /* Project object */;
492 | }
493 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-OHAttributedStringAdditions/Pods-OHAttributedStringAdditions-Private.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods-OHAttributedStringAdditions.xcconfig"
2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
3 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/OHAttributedStringAdditions" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/OHAttributedStringAdditions"
4 | OTHER_LDFLAGS = -ObjC
5 | PODS_ROOT = ${SRCROOT}
6 | SKIP_INSTALL = YES
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-OHAttributedStringAdditions/Pods-OHAttributedStringAdditions-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Pods_OHAttributedStringAdditions : NSObject
3 | @end
4 | @implementation PodsDummy_Pods_OHAttributedStringAdditions
5 | @end
6 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-OHAttributedStringAdditions/Pods-OHAttributedStringAdditions-prefix.pch:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #endif
4 |
5 | #import "Pods-environment.h"
6 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-OHAttributedStringAdditions/Pods-OHAttributedStringAdditions.xcconfig:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AliSoftware/OHAttributedStringAdditions/15d5d01c917ab60ac0be3ece523229a3de44a866/Example/Pods/Target Support Files/Pods-OHAttributedStringAdditions/Pods-OHAttributedStringAdditions.xcconfig
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods/Pods-acknowledgements.markdown:
--------------------------------------------------------------------------------
1 | # Acknowledgements
2 | This application makes use of the following third party libraries:
3 |
4 | ## OHAttributedStringAdditions
5 |
6 | The MIT License (MIT)
7 |
8 | Copyright (c) 2014 AliSoftware
9 |
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 |
17 | The above copyright notice and this permission notice shall be included in all
18 | copies or substantial portions of the Software.
19 |
20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 | SOFTWARE.
27 |
28 | Generated by CocoaPods - http://cocoapods.org
29 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods/Pods-acknowledgements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreferenceSpecifiers
6 |
7 |
8 | FooterText
9 | This application makes use of the following third party libraries:
10 | Title
11 | Acknowledgements
12 | Type
13 | PSGroupSpecifier
14 |
15 |
16 | FooterText
17 | The MIT License (MIT)
18 |
19 | Copyright (c) 2014 AliSoftware
20 |
21 | Permission is hereby granted, free of charge, to any person obtaining a copy
22 | of this software and associated documentation files (the "Software"), to deal
23 | in the Software without restriction, including without limitation the rights
24 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25 | copies of the Software, and to permit persons to whom the Software is
26 | furnished to do so, subject to the following conditions:
27 |
28 | The above copyright notice and this permission notice shall be included in all
29 | copies or substantial portions of the Software.
30 |
31 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
37 | SOFTWARE.
38 |
39 | Title
40 | OHAttributedStringAdditions
41 | Type
42 | PSGroupSpecifier
43 |
44 |
45 | FooterText
46 | Generated by CocoaPods - http://cocoapods.org
47 | Title
48 |
49 | Type
50 | PSGroupSpecifier
51 |
52 |
53 | StringsTable
54 | Acknowledgements
55 | Title
56 | Acknowledgements
57 |
58 |
59 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods/Pods-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Pods : NSObject
3 | @end
4 | @implementation PodsDummy_Pods
5 | @end
6 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods/Pods-environment.h:
--------------------------------------------------------------------------------
1 |
2 | // To check if a library is compiled with CocoaPods you
3 | // can use the `COCOAPODS` macro definition which is
4 | // defined in the xcconfigs so it is available in
5 | // headers also when they are imported in the client
6 | // project.
7 |
8 |
9 | // OHAttributedStringAdditions
10 | #define COCOAPODS_POD_AVAILABLE_OHAttributedStringAdditions
11 | #define COCOAPODS_VERSION_MAJOR_OHAttributedStringAdditions 1
12 | #define COCOAPODS_VERSION_MINOR_OHAttributedStringAdditions 3
13 | #define COCOAPODS_VERSION_PATCH_OHAttributedStringAdditions 0
14 |
15 | // OHAttributedStringAdditions/Base
16 | #define COCOAPODS_POD_AVAILABLE_OHAttributedStringAdditions_Base
17 | #define COCOAPODS_VERSION_MAJOR_OHAttributedStringAdditions_Base 1
18 | #define COCOAPODS_VERSION_MINOR_OHAttributedStringAdditions_Base 3
19 | #define COCOAPODS_VERSION_PATCH_OHAttributedStringAdditions_Base 0
20 |
21 | // OHAttributedStringAdditions/UILabel
22 | #define COCOAPODS_POD_AVAILABLE_OHAttributedStringAdditions_UILabel
23 | #define COCOAPODS_VERSION_MAJOR_OHAttributedStringAdditions_UILabel 1
24 | #define COCOAPODS_VERSION_MINOR_OHAttributedStringAdditions_UILabel 3
25 | #define COCOAPODS_VERSION_PATCH_OHAttributedStringAdditions_UILabel 0
26 |
27 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods/Pods-resources.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 |
4 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
5 |
6 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt
7 | > "$RESOURCES_TO_COPY"
8 |
9 | XCASSET_FILES=""
10 |
11 | install_resource()
12 | {
13 | case $1 in
14 | *.storyboard)
15 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc ${PODS_ROOT}/$1 --sdk ${SDKROOT}"
16 | ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc" "${PODS_ROOT}/$1" --sdk "${SDKROOT}"
17 | ;;
18 | *.xib)
19 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib ${PODS_ROOT}/$1 --sdk ${SDKROOT}"
20 | ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib" "${PODS_ROOT}/$1" --sdk "${SDKROOT}"
21 | ;;
22 | *.framework)
23 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
24 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
25 | echo "rsync -av ${PODS_ROOT}/$1 ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
26 | rsync -av "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
27 | ;;
28 | *.xcdatamodel)
29 | echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1"`.mom\""
30 | xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodel`.mom"
31 | ;;
32 | *.xcdatamodeld)
33 | echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd\""
34 | xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd"
35 | ;;
36 | *.xcmappingmodel)
37 | echo "xcrun mapc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm\""
38 | xcrun mapc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm"
39 | ;;
40 | *.xcassets)
41 | XCASSET_FILES="$XCASSET_FILES '$1'"
42 | ;;
43 | /*)
44 | echo "$1"
45 | echo "$1" >> "$RESOURCES_TO_COPY"
46 | ;;
47 | *)
48 | echo "${PODS_ROOT}/$1"
49 | echo "${PODS_ROOT}/$1" >> "$RESOURCES_TO_COPY"
50 | ;;
51 | esac
52 | }
53 |
54 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
55 | if [[ "${ACTION}" == "install" ]]; then
56 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
57 | fi
58 | rm -f "$RESOURCES_TO_COPY"
59 |
60 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n $XCASSET_FILES ]
61 | then
62 | case "${TARGETED_DEVICE_FAMILY}" in
63 | 1,2)
64 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
65 | ;;
66 | 1)
67 | TARGET_DEVICE_ARGS="--target-device iphone"
68 | ;;
69 | 2)
70 | TARGET_DEVICE_ARGS="--target-device ipad"
71 | ;;
72 | *)
73 | TARGET_DEVICE_ARGS="--target-device mac"
74 | ;;
75 | esac
76 | echo $XCASSET_FILES | xargs actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${IPHONEOS_DEPLOYMENT_TARGET}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
77 | fi
78 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods/Pods.debug.xcconfig:
--------------------------------------------------------------------------------
1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
2 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/OHAttributedStringAdditions"
3 | OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/OHAttributedStringAdditions"
4 | OTHER_LDFLAGS = $(inherited) -ObjC -l"Pods-OHAttributedStringAdditions"
5 | OTHER_LIBTOOLFLAGS = $(OTHER_LDFLAGS)
6 | PODS_ROOT = ${SRCROOT}/Pods
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods/Pods.release.xcconfig:
--------------------------------------------------------------------------------
1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
2 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/OHAttributedStringAdditions"
3 | OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/OHAttributedStringAdditions"
4 | OTHER_LDFLAGS = $(inherited) -ObjC -l"Pods-OHAttributedStringAdditions"
5 | OTHER_LIBTOOLFLAGS = $(OTHER_LDFLAGS)
6 | PODS_ROOT = ${SRCROOT}/Pods
--------------------------------------------------------------------------------
/Example/UnitTests/NSMutableAttributedStringTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSMutableAttributedStringTests.m
3 | // AttributedStringDemo
4 | //
5 | // Created by Olivier Halligon on 17/08/2014.
6 | // Copyright (c) 2014 AliSoftware. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 | #import
12 |
13 | #import "OHASATestHelper.h"
14 |
15 | @interface NSMutableAttributedStringTests : XCTestCase @end
16 |
17 | @implementation NSMutableAttributedStringTests
18 |
19 | /******************************************************************************/
20 | #pragma mark - Text Font
21 |
22 | - (void)test_setFont
23 | {
24 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
25 | UIFont* font = [UIFont fontWithPostscriptName:@"Courier" size:42];
26 | [str setFont:font];
27 |
28 | NSSet* attr = attributesSetInString(str);
29 | NSSet* expectedAttributes = [NSSet setWithObject: @[@0,@11,@{NSFontAttributeName:font}] ];
30 |
31 | XCTAssertEqualObjects(attr, expectedAttributes);
32 | }
33 |
34 | - (void)test_setFont_range
35 | {
36 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
37 | UIFont* font = [UIFont fontWithPostscriptName:@"Courier" size:42];
38 | [str setFont:font range:NSMakeRange(4,2)];
39 |
40 | NSSet* attr = attributesSetInString(str);
41 | NSSet* expectedAttributes = [NSSet setWithObject: @[@4,@2,@{NSFontAttributeName:font}] ];
42 |
43 | XCTAssertEqualObjects(attr, expectedAttributes);
44 | }
45 |
46 | /******************************************************************************/
47 | #pragma mark - Text Color
48 |
49 | - (void)test_setTextColor
50 | {
51 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
52 | UIColor* color = [UIColor purpleColor];
53 | [str setTextColor:color];
54 |
55 | NSSet* attr = attributesSetInString(str);
56 | NSSet* expectedAttributes = [NSSet setWithObject: @[@0,@11,@{NSForegroundColorAttributeName:color}] ];
57 |
58 | XCTAssertEqualObjects(attr, expectedAttributes);
59 | }
60 |
61 | - (void)test_setTextColor_range
62 | {
63 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
64 | UIColor* color = [UIColor purpleColor];
65 | [str setTextColor:color range:NSMakeRange(4, 2)];
66 |
67 | NSSet* attr = attributesSetInString(str);
68 | NSSet* expectedAttributes = [NSSet setWithObject: @[@4,@2,@{NSForegroundColorAttributeName:color}] ];
69 |
70 | XCTAssertEqualObjects(attr, expectedAttributes);
71 | }
72 |
73 | - (void)test_setTextBackgroundColor
74 | {
75 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
76 | UIColor* color = [UIColor purpleColor];
77 | [str setTextBackgroundColor:color];
78 |
79 | NSSet* attr = attributesSetInString(str);
80 | NSSet* expectedAttributes = [NSSet setWithObject: @[@0,@11,@{NSBackgroundColorAttributeName:color}] ];
81 |
82 | XCTAssertEqualObjects(attr, expectedAttributes);
83 | }
84 |
85 | - (void)test_setTextBackgroundColor_range
86 | {
87 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
88 | UIColor* color = [UIColor purpleColor];
89 | [str setTextBackgroundColor:color range:NSMakeRange(4, 2)];
90 |
91 | NSSet* attr = attributesSetInString(str);
92 | NSSet* expectedAttributes = [NSSet setWithObject: @[@4,@2,@{NSBackgroundColorAttributeName:color}] ];
93 |
94 | XCTAssertEqualObjects(attr, expectedAttributes);
95 | }
96 |
97 | /******************************************************************************/
98 | #pragma mark - Text Underlining
99 |
100 | - (void)test_setTextUnderlined_YES
101 | {
102 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
103 | [str setTextUnderlined:YES];
104 |
105 | NSSet* attr = attributesSetInString(str);
106 | NSSet* expectedAttributes = [NSSet setWithObject: @[@0,@11,@{NSUnderlineStyleAttributeName:@(NSUnderlineStyleSingle|NSUnderlinePatternSolid)}] ];
107 |
108 | XCTAssertEqualObjects(attr, expectedAttributes);
109 | }
110 |
111 | - (void)test_setTextUnderlined_NO
112 | {
113 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
114 | [str setTextUnderlined:NO];
115 |
116 | NSSet* attr = attributesSetInString(str);
117 | NSSet* expectedAttributes = [NSSet setWithObject: @[@0,@11,@{NSUnderlineStyleAttributeName:@(NSUnderlineStyleNone)}] ];
118 |
119 | XCTAssertEqualObjects(attr, expectedAttributes);
120 | }
121 |
122 | - (void)test_setTextUnderlined_range
123 | {
124 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
125 | [str setTextUnderlined:YES range:NSMakeRange(4, 2)];
126 |
127 | NSSet* attr = attributesSetInString(str);
128 | NSSet* expectedAttributes = [NSSet setWithObject: @[@4,@2,@{NSUnderlineStyleAttributeName:@(NSUnderlineStyleSingle|NSUnderlinePatternSolid)}] ];
129 |
130 | XCTAssertEqualObjects(attr, expectedAttributes);
131 | }
132 |
133 | - (void)test_setTextUnderlineStyle_range
134 | {
135 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
136 | NSUnderlineStyle style = NSUnderlinePatternDashDotDot | NSUnderlineStyleDouble;
137 | [str setTextUnderlineStyle:style range:NSMakeRange(4, 2)];
138 |
139 | NSSet* attr = attributesSetInString(str);
140 | NSSet* expectedAttributes = [NSSet setWithObject: @[@4,@2,@{NSUnderlineStyleAttributeName:@(style)}] ];
141 |
142 | XCTAssertEqualObjects(attr, expectedAttributes);
143 | }
144 |
145 | - (void)test_setTextUnderlineColor
146 | {
147 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
148 | UIColor* color = [UIColor orangeColor];
149 | [str setTextUnderlineColor:color];
150 |
151 | NSSet* attr = attributesSetInString(str);
152 | NSSet* expectedAttributes = [NSSet setWithObject: @[@0,@11,@{NSUnderlineColorAttributeName:color}] ];
153 |
154 | XCTAssertEqualObjects(attr, expectedAttributes);
155 | }
156 |
157 | - (void)test_setTextUnderlineColor_range
158 | {
159 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
160 | UIColor* color = [UIColor orangeColor];
161 | [str setTextUnderlineColor:color range:NSMakeRange(4, 2)];
162 |
163 | NSSet* attr = attributesSetInString(str);
164 | NSSet* expectedAttributes = [NSSet setWithObject: @[@4,@2,@{NSUnderlineColorAttributeName:color}] ];
165 |
166 | XCTAssertEqualObjects(attr, expectedAttributes);
167 | }
168 |
169 | /******************************************************************************/
170 | #pragma mark - Text Style & Traits
171 |
172 | - (void)test_changeFontTraitsWithBlock
173 | {
174 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
175 | UIFont* font1 = [UIFont fontWithPostscriptName:@"HelveticaNeue" size:42];
176 | [str addAttribute:NSFontAttributeName value:font1 range:NSMakeRange(0, 11)];
177 | UIFont* font2 = [UIFont fontWithPostscriptName:@"Courier" size:19];
178 | [str addAttribute:NSFontAttributeName value:font2 range:NSMakeRange(4, 2)];
179 |
180 | [str changeFontTraitsWithBlock:^UIFontDescriptorSymbolicTraits(UIFontDescriptorSymbolicTraits currentTraits, NSRange _) {
181 | return currentTraits | UIFontDescriptorTraitBold;
182 | }];
183 |
184 | NSSet* attr = attributesSetInString(str);
185 |
186 | UIFont* font1Bold = [UIFont fontWithPostscriptName:@"HelveticaNeue-Bold" size:42];
187 | UIFont* font2Bold = [UIFont fontWithPostscriptName:@"Courier-Bold" size:19];
188 | NSSet* expectedAttributes = [NSSet setWithObjects:
189 | @[@0,@4,@{NSFontAttributeName:font1Bold}],
190 | @[@4,@2,@{NSFontAttributeName:font2Bold}],
191 | @[@6,@5,@{NSFontAttributeName:font1Bold}],
192 | nil];
193 |
194 | XCTAssertEqualObjects(attr, expectedAttributes);
195 | }
196 |
197 | - (void)test_changeFontTraitsInRange_withBlock
198 | {
199 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
200 | UIFont* font1 = [UIFont fontWithPostscriptName:@"HelveticaNeue" size:42];
201 | [str addAttribute:NSFontAttributeName value:font1 range:NSMakeRange(0, 11)];
202 | UIFont* font2 = [UIFont fontWithPostscriptName:@"Courier" size:19];
203 | [str addAttribute:NSFontAttributeName value:font2 range:NSMakeRange(4, 2)];
204 |
205 | [str changeFontTraitsInRange:NSMakeRange(5, 3) withBlock:^UIFontDescriptorSymbolicTraits(UIFontDescriptorSymbolicTraits currentTraits, NSRange _) {
206 | return currentTraits | UIFontDescriptorTraitBold;
207 | }];
208 |
209 | NSSet* attr = attributesSetInString(str);
210 |
211 | UIFont* font1Bold = [UIFont fontWithPostscriptName:@"HelveticaNeue-Bold" size:42];
212 | UIFont* font2Bold = [UIFont fontWithPostscriptName:@"Courier-Bold" size:19];
213 | NSSet* expectedAttributes = [NSSet setWithObjects:
214 | @[@0,@4,@{NSFontAttributeName:font1}],
215 | @[@4,@1,@{NSFontAttributeName:font2}],
216 | @[@5,@1,@{NSFontAttributeName:font2Bold}],
217 | @[@6,@2,@{NSFontAttributeName:font1Bold}],
218 | @[@8,@3,@{NSFontAttributeName:font1}],
219 | nil];
220 |
221 | XCTAssertEqualObjects(attr, expectedAttributes);
222 | }
223 |
224 | - (void)test_setFontBold_YES
225 | {
226 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
227 | UIFont* font = [UIFont fontWithPostscriptName:@"HelveticaNeue" size:42];
228 | [str addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, 11)];
229 | [str setFontBold:YES];
230 |
231 | NSSet* attr = attributesSetInString(str);
232 | UIFont* fontBold = [UIFont fontWithPostscriptName:@"HelveticaNeue-Bold" size:42];
233 | NSSet* expectedAttributes = [NSSet setWithObject: @[@0,@11,@{NSFontAttributeName:fontBold}] ];
234 |
235 | XCTAssertEqualObjects(attr, expectedAttributes);
236 | }
237 |
238 | - (void)test_setFontBold_NO
239 | {
240 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
241 | UIFont* font = [UIFont fontWithPostscriptName:@"HelveticaNeue-Bold" size:42];
242 | [str addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, 11)];
243 | [str setFontBold:NO];
244 |
245 | NSSet* attr = attributesSetInString(str);
246 | UIFont* fontNoBold = [UIFont fontWithPostscriptName:@"HelveticaNeue" size:42];
247 | NSSet* expectedAttributes = [NSSet setWithObject: @[@0,@11,@{NSFontAttributeName:fontNoBold}] ];
248 |
249 | XCTAssertEqualObjects(attr, expectedAttributes);
250 | }
251 |
252 | - (void)test_setFontBold_range_YES
253 | {
254 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
255 | UIFont* font = [UIFont fontWithPostscriptName:@"HelveticaNeue" size:42];
256 | [str addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, 11)];
257 | [str setFontBold:YES range:NSMakeRange(4, 2)];
258 |
259 | NSSet* attr = attributesSetInString(str);
260 | UIFont* fontBold = [UIFont fontWithPostscriptName:@"HelveticaNeue-Bold" size:42];
261 | NSSet* expectedAttributes = [NSSet setWithObjects:
262 | @[@0,@4,@{NSFontAttributeName:font}],
263 | @[@4,@2,@{NSFontAttributeName:fontBold}],
264 | @[@6,@5,@{NSFontAttributeName:font}],
265 | nil];
266 |
267 | XCTAssertEqualObjects(attr, expectedAttributes);
268 | }
269 |
270 | - (void)test_setFontBold_range_NO
271 | {
272 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
273 | UIFont* font = [UIFont fontWithPostscriptName:@"HelveticaNeue-Bold" size:42];
274 | [str addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, 11)];
275 | [str setFontBold:NO range:NSMakeRange(4, 2)];
276 |
277 | NSSet* attr = attributesSetInString(str);
278 | UIFont* fontNoBold = [UIFont fontWithPostscriptName:@"HelveticaNeue" size:42];
279 | NSSet* expectedAttributes = [NSSet setWithObjects:
280 | @[@0,@4,@{NSFontAttributeName:font}],
281 | @[@4,@2,@{NSFontAttributeName:fontNoBold}],
282 | @[@6,@5,@{NSFontAttributeName:font}],
283 | nil];
284 |
285 | XCTAssertEqualObjects(attr, expectedAttributes);
286 | }
287 |
288 | - (void)test_setFontItalics_NO
289 | {
290 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
291 | UIFont* font = [UIFont fontWithPostscriptName:@"HelveticaNeue" size:42];
292 | [str addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, 11)];
293 | [str setFontItalics:YES];
294 |
295 | NSSet* attr = attributesSetInString(str);
296 | UIFont* fontItalic = [UIFont fontWithPostscriptName:@"HelveticaNeue-Italic" size:42];
297 | NSSet* expectedAttributes = [NSSet setWithObject: @[@0,@11,@{NSFontAttributeName:fontItalic}] ];
298 |
299 | XCTAssertEqualObjects(attr, expectedAttributes);
300 | }
301 |
302 | - (void)test_setFontItalics_YES
303 | {
304 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
305 | UIFont* font = [UIFont fontWithPostscriptName:@"HelveticaNeue-Italic" size:42];
306 | [str addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, 11)];
307 | [str setFontItalics:NO];
308 |
309 | NSSet* attr = attributesSetInString(str);
310 | UIFont* fontNoItalic = [UIFont fontWithPostscriptName:@"HelveticaNeue" size:42];
311 | NSSet* expectedAttributes = [NSSet setWithObject: @[@0,@11,@{NSFontAttributeName:fontNoItalic}] ];
312 |
313 | XCTAssertEqualObjects(attr, expectedAttributes);
314 | }
315 |
316 | - (void)test_setFontItalics_range_YES
317 | {
318 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
319 | UIFont* font = [UIFont fontWithPostscriptName:@"HelveticaNeue" size:42];
320 | [str addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, 11)];
321 | [str setFontItalics:YES range:NSMakeRange(4, 2)];
322 |
323 | NSSet* attr = attributesSetInString(str);
324 | UIFont* fontItalic = [UIFont fontWithPostscriptName:@"HelveticaNeue-Italic" size:42];
325 | NSSet* expectedAttributes = [NSSet setWithObjects:
326 | @[@0,@4,@{NSFontAttributeName:font}],
327 | @[@4,@2,@{NSFontAttributeName:fontItalic}],
328 | @[@6,@5,@{NSFontAttributeName:font}],
329 | nil];
330 |
331 | XCTAssertEqualObjects(attr, expectedAttributes);
332 | }
333 |
334 | - (void)test_setFontItalics_range_NO
335 | {
336 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
337 | UIFont* font = [UIFont fontWithPostscriptName:@"HelveticaNeue-Italic" size:42];
338 | [str addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, 11)];
339 | [str setFontItalics:NO range:NSMakeRange(4, 2)];
340 |
341 | NSSet* attr = attributesSetInString(str);
342 | UIFont* fontNoItalic = [UIFont fontWithPostscriptName:@"HelveticaNeue" size:42];
343 | NSSet* expectedAttributes = [NSSet setWithObjects:
344 | @[@0,@4,@{NSFontAttributeName:font}],
345 | @[@4,@2,@{NSFontAttributeName:fontNoItalic}],
346 | @[@6,@5,@{NSFontAttributeName:font}],
347 | nil];
348 |
349 | XCTAssertEqualObjects(attr, expectedAttributes);
350 | }
351 |
352 | /******************************************************************************/
353 | #pragma mark - Link
354 |
355 | - (void)test_setURL_range
356 | {
357 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
358 | NSURL* url = [NSURL URLWithString:@"foo://bar"];
359 | [str addAttribute:NSLinkAttributeName value:url range:NSMakeRange(4, 2)];
360 |
361 | NSSet* attr = attributesSetInString(str);
362 | NSSet* expectedAttributes = [NSSet setWithObject:@[@4,@2,@{NSLinkAttributeName:url}]];
363 |
364 | XCTAssertEqualObjects(attr, expectedAttributes);
365 | }
366 |
367 | /******************************************************************************/
368 | #pragma mark - Character Spacing
369 |
370 | - (void)test_setCharacterSpacing
371 | {
372 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
373 | [str setCharacterSpacing:42];
374 |
375 | NSSet* attr = attributesSetInString(str);
376 | NSSet* expectedAttributes = [NSSet setWithObject:@[@0,@11,@{NSKernAttributeName: @42}]];
377 |
378 | XCTAssertEqualObjects(attr, expectedAttributes);
379 | }
380 |
381 | - (void)test_setCharacterSpacing_range
382 | {
383 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
384 | [str setCharacterSpacing:42 range:NSMakeRange(4, 2)];
385 |
386 | NSSet* attr = attributesSetInString(str);
387 | NSSet* expectedAttributes = [NSSet setWithObject:@[@4,@2,@{NSKernAttributeName: @42}]];
388 |
389 | XCTAssertEqualObjects(attr, expectedAttributes);
390 | }
391 |
392 | /******************************************************************************/
393 | #pragma mark - Subscript and Superscript
394 |
395 | - (void)test_setBaselineOffset
396 | {
397 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
398 | [str setBaselineOffset:42];
399 |
400 | NSSet* attr = attributesSetInString(str);
401 | NSSet* expectedAttributes = [NSSet setWithObject:@[@0,@11,@{NSBaselineOffsetAttributeName:@42}]];
402 |
403 | XCTAssertEqualObjects(attr, expectedAttributes);
404 | }
405 |
406 | - (void)test_setBaselineOffset_range
407 | {
408 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
409 | [str setBaselineOffset:42 range:NSMakeRange(4, 2)];
410 |
411 | NSSet* attr = attributesSetInString(str);
412 | NSSet* expectedAttributes = [NSSet setWithObject:@[@4,@2,@{NSBaselineOffsetAttributeName:@42}]];
413 |
414 | XCTAssertEqualObjects(attr, expectedAttributes);
415 | }
416 |
417 | - (void)test_setSuperscriptForRange
418 | {
419 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
420 | UIFont* font = [UIFont fontWithPostscriptName:@"Helvetica" size:42];
421 | [str addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, 11)];
422 | [str setSuperscriptForRange:NSMakeRange(4, 2)];
423 |
424 | NSSet* attr = attributesSetInString(str);
425 | NSSet* expectedAttributes = [NSSet setWithObjects:
426 | @[@0,@4,@{NSFontAttributeName:font}],
427 | @[@4,@2,@{NSFontAttributeName:font, NSBaselineOffsetAttributeName:@(21)}],
428 | @[@6,@5,@{NSFontAttributeName:font}],
429 | nil];
430 |
431 | XCTAssertEqualObjects(attr, expectedAttributes);
432 | }
433 |
434 | - (void)test_setSubscriptForRange
435 | {
436 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
437 | UIFont* font = [UIFont fontWithPostscriptName:@"Helvetica" size:42];
438 | [str addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, 11)];
439 | [str setSubscriptForRange:NSMakeRange(4, 2)];
440 |
441 | NSSet* attr = attributesSetInString(str);
442 | NSSet* expectedAttributes = [NSSet setWithObjects:
443 | @[@0,@4,@{NSFontAttributeName:font}],
444 | @[@4,@2,@{NSFontAttributeName:font, NSBaselineOffsetAttributeName:@(-21)}],
445 | @[@6,@5,@{NSFontAttributeName:font}],
446 | nil];
447 |
448 | XCTAssertEqualObjects(attr, expectedAttributes);
449 | }
450 |
451 | /******************************************************************************/
452 | #pragma mark - Paragraph Style
453 |
454 | - (void)test_setTextAlignment
455 | {
456 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
457 | [str setTextAlignment:NSTextAlignmentJustified];
458 |
459 | NSSet* attr = attributesSetInString(str);
460 | NSMutableParagraphStyle* style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
461 | style.alignment = NSTextAlignmentJustified;
462 | NSSet* expectedAttributes = [NSSet setWithObject:@[@0,@11,@{NSParagraphStyleAttributeName:style}]];
463 |
464 | XCTAssertEqualObjects(attr, expectedAttributes);
465 | }
466 |
467 | - (void)test_setTextAlignment_range
468 | {
469 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
470 | [str setTextAlignment:NSTextAlignmentJustified range:NSMakeRange(4, 2)];
471 |
472 | NSSet* attr = attributesSetInString(str);
473 | NSMutableParagraphStyle* style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
474 | style.alignment = NSTextAlignmentJustified;
475 | NSSet* expectedAttributes = [NSSet setWithObject:@[@4,@2,@{NSParagraphStyleAttributeName:style}]];
476 |
477 | XCTAssertEqualObjects(attr, expectedAttributes);
478 |
479 | }
480 |
481 |
482 | - (void)test_setLineBreakMode
483 | {
484 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
485 | [str setLineBreakMode:NSLineBreakByTruncatingMiddle];
486 |
487 | NSSet* attr = attributesSetInString(str);
488 | NSMutableParagraphStyle* style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
489 | style.lineBreakMode = NSLineBreakByTruncatingMiddle;
490 | NSSet* expectedAttributes = [NSSet setWithObject:@[@0,@11,@{NSParagraphStyleAttributeName:style}]];
491 |
492 | XCTAssertEqualObjects(attr, expectedAttributes);
493 | }
494 |
495 | - (void)test_setLineBreakMode_range
496 | {
497 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
498 | [str setLineBreakMode:NSLineBreakByTruncatingMiddle range:NSMakeRange(4, 2)];
499 |
500 | NSSet* attr = attributesSetInString(str);
501 | NSMutableParagraphStyle* style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
502 | style.lineBreakMode = NSLineBreakByTruncatingMiddle;
503 | NSSet* expectedAttributes = [NSSet setWithObject:@[@4,@2,@{NSParagraphStyleAttributeName:style}]];
504 |
505 | XCTAssertEqualObjects(attr, expectedAttributes);
506 | }
507 |
508 | - (void)test_changeParagraphStylesWithBlock
509 | {
510 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
511 | NSMutableParagraphStyle* styleMiddle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
512 | styleMiddle.firstLineHeadIndent = 42;
513 | [str addAttribute:NSParagraphStyleAttributeName value:styleMiddle range:NSMakeRange(4, 2)];
514 |
515 | [str changeParagraphStylesWithBlock:^(NSMutableParagraphStyle *currentStyle, NSRange aRange) {
516 | currentStyle.lineSpacing = 29;
517 | }];
518 |
519 | NSSet* attr = attributesSetInString(str);
520 | NSMutableParagraphStyle* styleOther = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
521 | styleMiddle.lineSpacing = 29;
522 | styleOther.lineSpacing = 29;
523 | NSSet* expectedAttributes = [NSSet setWithObjects:
524 | @[@0,@4,@{NSParagraphStyleAttributeName:styleOther}],
525 | @[@4,@2,@{NSParagraphStyleAttributeName:styleMiddle}],
526 | @[@6,@5,@{NSParagraphStyleAttributeName:styleOther}],
527 | nil];
528 |
529 | XCTAssertEqualObjects(attr, expectedAttributes);
530 | }
531 |
532 | - (void)test_changeParagraphStylesInRange_withBlock
533 | {
534 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
535 | NSMutableParagraphStyle* styleMiddleOriginal = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
536 | styleMiddleOriginal.firstLineHeadIndent = 42;
537 | [str addAttribute:NSParagraphStyleAttributeName value:styleMiddleOriginal range:NSMakeRange(4, 2)];
538 |
539 | [str changeParagraphStylesInRange:NSMakeRange(5, 3) withBlock:^(NSMutableParagraphStyle *currentStyle, NSRange aRange) {
540 | currentStyle.lineSpacing = 29;
541 | }];
542 |
543 | NSSet* attr = attributesSetInString(str);
544 | NSMutableParagraphStyle* styleOtherModified = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
545 | NSMutableParagraphStyle* styleMiddleModified = [styleMiddleOriginal mutableCopy];
546 | styleMiddleModified.lineSpacing = 29;
547 | styleOtherModified.lineSpacing = 29;
548 | NSSet* expectedAttributes = [NSSet setWithObjects:
549 | @[@4,@1,@{NSParagraphStyleAttributeName:styleMiddleOriginal}],
550 | @[@5,@1,@{NSParagraphStyleAttributeName:styleMiddleModified}],
551 | @[@6,@2,@{NSParagraphStyleAttributeName:styleOtherModified}],
552 | nil];
553 |
554 | XCTAssertEqualObjects(attr, expectedAttributes);
555 | }
556 |
557 | - (void)test_setParagraphStyle
558 | {
559 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
560 | NSMutableParagraphStyle* style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
561 | style.firstLineHeadIndent = 42;
562 | style.lineSpacing = 29;
563 | style.defaultTabInterval = 37;
564 | style.paragraphSpacing = 18;
565 | style.alignment = NSTextAlignmentRight;
566 |
567 | [str setParagraphStyle:style];
568 |
569 | NSSet* attr = attributesSetInString(str);
570 | NSSet* expectedAttributes = [NSSet setWithObject:@[@0,@11,@{NSParagraphStyleAttributeName:style}]];
571 |
572 | XCTAssertEqualObjects(attr, expectedAttributes);
573 | }
574 |
575 | - (void)test_setParagraphStyle_range
576 | {
577 | NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithString:@"Hello world"];
578 | NSMutableParagraphStyle* style1 = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
579 | style1.lineSpacing = 73;
580 | style1.tailIndent = 19;
581 | [str setParagraphStyle:style1 range:NSMakeRange(3, 4)];
582 |
583 | NSMutableParagraphStyle* style2 = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
584 | style2.firstLineHeadIndent = 42;
585 | style2.lineSpacing = 29;
586 | style2.defaultTabInterval = 37;
587 | style2.paragraphSpacing = 18;
588 | style2.alignment = NSTextAlignmentRight;
589 | [str setParagraphStyle:style2 range:NSMakeRange(4, 2)];
590 |
591 | NSSet* attr = attributesSetInString(str);
592 | NSSet* expectedAttributes = [NSSet setWithObjects:
593 | @[@3,@1,@{NSParagraphStyleAttributeName:style1}],
594 | @[@4,@2,@{NSParagraphStyleAttributeName:style2}],
595 | @[@6,@1,@{NSParagraphStyleAttributeName:style1}],
596 | nil];
597 |
598 | XCTAssertEqualObjects(attr, expectedAttributes);
599 | }
600 |
601 | @end
602 |
--------------------------------------------------------------------------------
/Example/UnitTests/OHASATestHelper.h:
--------------------------------------------------------------------------------
1 | //
2 | // OHASATestHelper.h
3 | // AttributedStringDemo
4 | //
5 | // Created by Olivier Halligon on 07/09/2014.
6 | // Copyright (c) 2014 AliSoftware. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface OHASATestHelper : NSObject
12 |
13 | @end
14 |
15 | NSSet* attributesSetInString(NSAttributedString* str);
16 |
--------------------------------------------------------------------------------
/Example/UnitTests/OHASATestHelper.m:
--------------------------------------------------------------------------------
1 | //
2 | // OHASATestHelper.m
3 | // AttributedStringDemo
4 | //
5 | // Created by Olivier Halligon on 07/09/2014.
6 | // Copyright (c) 2014 AliSoftware. All rights reserved.
7 | //
8 |
9 | #import "OHASATestHelper.h"
10 |
11 | @implementation OHASATestHelper
12 |
13 | @end
14 |
15 | NSSet* attributesSetInString(NSAttributedString* str)
16 | {
17 | NSMutableSet* set = [NSMutableSet set];
18 | [str enumerateAttributesInRange:NSMakeRange(0, str.length)
19 | options:0
20 | usingBlock:^(NSDictionary *attrs, NSRange range, BOOL *stop)
21 | {
22 | if (attrs.count > 0) [set addObject:@[@(range.location),@(range.length),attrs]];
23 | }];
24 | return [NSSet setWithSet:set];
25 | }
26 |
27 |
--------------------------------------------------------------------------------
/Example/UnitTests/UIFontTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // AttributedStringDemoTests.m
3 | // AttributedStringDemoTests
4 | //
5 | // Created by Olivier Halligon on 13/08/2014.
6 | // Copyright (c) 2014 AliSoftware. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 | #import "OHASATestHelper.h"
12 |
13 | @interface UIFontTests : XCTestCase @end
14 |
15 | @implementation UIFontTests
16 |
17 | - (void)test_fontWithFamily_size_bold_italic_01
18 | {
19 | UIFont* font = [UIFont fontWithFamily:@"Helvetica" size:42 bold:NO italic:NO];
20 | XCTAssertEqualObjects(font.fontDescriptor.postscriptName, @"Helvetica");
21 | XCTAssertEqual(font.pointSize, 42);
22 | }
23 |
24 | - (void)test_fontWithFamily_size_bold_italic_02
25 | {
26 | UIFont* font = [UIFont fontWithFamily:@"Helvetica" size:42 bold:NO italic:YES];
27 | XCTAssertEqualObjects(font.fontDescriptor.postscriptName, @"Helvetica-Oblique");
28 | XCTAssertEqual(font.pointSize, 42);
29 | }
30 |
31 | - (void)test_fontWithFamily_size_bold_italic_03
32 | {
33 | UIFont* font = [UIFont fontWithFamily:@"Helvetica" size:42 bold:YES italic:NO];
34 | XCTAssertEqualObjects(font.fontDescriptor.postscriptName, @"Helvetica-Bold");
35 | XCTAssertEqual(font.pointSize, 42);
36 | }
37 |
38 | - (void)test_fontWithFamily_size_bold_italic_04
39 | {
40 | UIFont* font = [UIFont fontWithFamily:@"Helvetica" size:42 bold:YES italic:YES];
41 | XCTAssertEqualObjects(font.fontDescriptor.postscriptName, @"Helvetica-BoldOblique");
42 | XCTAssertEqual(font.pointSize, 42);
43 | }
44 |
45 | - (void)test_fontWithFamily_size_bold_italic_05
46 | {
47 | UIFont* font = [UIFont fontWithFamily:@"Zxqvz9pmq" size:42 bold:YES italic:YES];
48 | XCTAssertEqualObjects(font.fontDescriptor.postscriptName, @"Helvetica");
49 | XCTAssertEqual(font.pointSize, 42);
50 | }
51 |
52 | - (void)test_fontWithFamily_size_traits
53 | {
54 | UIFontDescriptorSymbolicTraits traits = UIFontDescriptorTraitCondensed | UIFontDescriptorTraitBold;
55 | UIFont* font = [UIFont fontWithFamily:@"Helvetica Neue" size:42 traits:traits];
56 | XCTAssertEqualObjects(font.fontDescriptor.postscriptName, @"HelveticaNeue-CondensedBold");
57 | XCTAssertEqual(font.pointSize, 42);
58 | }
59 |
60 | - (void)test_fontWithPostscriptName_size
61 | {
62 | UIFont* font = [UIFont fontWithPostscriptName:@"HelveticaNeue-Bold" size:37];
63 | XCTAssertEqualObjects(font.fontDescriptor.postscriptName, @"HelveticaNeue-Bold");
64 | XCTAssertEqual(font.pointSize, 37);
65 | }
66 |
67 | - (void)test_fontWithSymbolicTraits
68 | {
69 | UIFont* baseFont = [UIFont fontWithPostscriptName:@"Helvetica Neue" size:42];
70 | UIFont* font = [baseFont fontWithSymbolicTraits:UIFontDescriptorTraitCondensed|UIFontDescriptorTraitBold];
71 | XCTAssertEqualObjects(font.fontDescriptor.postscriptName, @"HelveticaNeue-CondensedBold");
72 | XCTAssertEqual(font.pointSize, 42);
73 |
74 | }
75 |
76 | - (void)test_symbolicTraits
77 | {
78 | UIFont* font = [UIFont fontWithPostscriptName:@"HelveticaNeue-CondensedBold" size:42];
79 | XCTAssertEqual(font.symbolicTraits, UIFontDescriptorTraitCondensed|UIFontDescriptorTraitBold);
80 | }
81 |
82 | @end
83 |
--------------------------------------------------------------------------------
/Example/UnitTests/UnitTests-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | com.alisoftware.${PRODUCT_NAME:rfc1034identifier}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundlePackageType
14 | BNDL
15 | CFBundleShortVersionString
16 | 1.0
17 | CFBundleSignature
18 | ????
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 AliSoftware
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/OHAttributedStringAdditions.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 |
3 | s.name = "OHAttributedStringAdditions"
4 | s.version = "1.3.0"
5 | s.summary = "Categories on NSAttributedString to add a lot of very useful convenience methods."
6 |
7 | s.description = <<-DESC.gsub(/^.*\|/,'')
8 | |This pod contains categories on `NSAttributedString` to add a lot of very useful
9 | |convenience methods to manipulate attributed strings.
10 | |
11 | |The includes convenience methods to:
12 | | * set attributes on a given range
13 | | * get attributes at a given index
14 | |
15 | |Convenience methods are available for a lot of common attributes, including:
16 | | * Fonts
17 | | * Text Foreground and Background Colors
18 | | * Text Style (bold, italics, underline)
19 | | * Links (URLs)
20 | | * Baseline offset, subscript, superscript
21 | | * Text alignment, linebreak mode, character spacing
22 | | * Paragraph Style (text indent, linespacing, …)
23 | | * etc.
24 | DESC
25 |
26 | s.homepage = "https://github.com/AliSoftware/OHAttributedStringAdditions"
27 | s.license = { :type => "MIT", :file => "LICENSE" }
28 |
29 |
30 | s.author = { "Olivier Halligon" => "olivier@halligon.net" }
31 | s.social_media_url = "http://twitter.com/aligatr"
32 |
33 | s.ios.deployment_target = "7.0"
34 | # s.osx.deployment_target = "10.8"
35 |
36 | s.source = { :git => "https://github.com/AliSoftware/OHAttributedStringAdditions.git", :tag => s.version.to_s }
37 | s.requires_arc = true
38 |
39 |
40 | ### Subspecs ###
41 |
42 | s.subspec 'Base' do |sub|
43 | sub.source_files = "Source/#{s.name}.h", "Source/{NSAttributedString,NSMutableAttributedString,UIFont}+OHAdditions.{h,m}"
44 | end
45 |
46 | s.subspec 'UILabel' do |sub|
47 | sub.source_files = "Source/UILabel+OHAdditions.{h,m}"
48 | sub.dependency "#{s.name}/Base"
49 | end
50 |
51 | end
52 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # OHAttributedStringAdditions
2 |
3 | [](http://cocoadocs.org/docsets/OHAttributedStringAdditions)
4 | [](http://cocoadocs.org/docsets/OHAttributedStringAdditions)
5 | [](https://travis-ci.org/AliSoftware/OHAttributedStringAdditions)
6 |
7 | This pod contains categories on `NSAttributedString` to add a lot of very useful convenience methods to manipulate attributed strings.
8 |
9 | Convenience methods include:
10 |
11 | * **font** manipulation (`setFont:range:` and `fontAtIndex:effectiveRange:`)
12 | * **text color** (`setTextColor:range:` and `textColorAtIndex:effectiveRange:`)
13 | * **background color**
14 | * **bold**, *italics* and *underline* styles
15 | * add **URLs** to your text
16 | * **paragraph styles** (**indentation**, **line spacing**, …)
17 | * baseline adjustment, **subscript**, **superscript**, …
18 | * And much more
19 |
20 | It also contains:
21 |
22 | * A category on `UIFont` to build a font given its postscript name and derive a bold/italic font from a standard one and vice-versa.
23 | * A category on `UILabel` to make it easier to detect the character at a given coordinate, which is useful to detect if the user tapped on a link (if the character as a given tapped `CGPoint` has an associated `NSURL`) and similar stuff
24 |
25 | > Note that for advanced URL detection, you should still prefer `UITextView` (configuring it with `editable=NO`) and its dedicated delegate methods instead of using `UILabel` (which does not publicly expose its `NSLayoutManager` to properly compute the exact way its characters are laid out, forcing us to recreate the TextKit objects ourselves, contrary to `UITextView`).
26 |
27 | ## Documentation
28 |
29 | The source code is fully commented and documentation is auto-generated [here](http://cocoadocs.org/docsets/OHAttributedStringAdditions).
30 |
31 | There is also some help pages [in the repository's wiki](https://github.com/AliSoftware/OHAttributedStringAdditions/wiki).
32 |
33 | ## Installation
34 |
35 | The suggested installation is via [CocoaPods](http://cocoapods.org/). Simply add the following line to your `Podfile`:
36 |
37 | ```
38 | pod 'OHAttributedStringAdditions'
39 | ```
40 |
41 | Then do a `pod install`.
42 |
43 | ## Example
44 |
45 | A demo project is provided in the repository. Don't hesitate to open `Example/AttributedStringDemo.xcworkspace` and play with it.
46 |
47 | If you have CocoaPods, you can even try that Sample project even if you don't have cloned the project yet, by using `pod try OHAttributedStringAdditions` in your terminal.
48 |
49 | 
50 |
51 | ## Future improvements
52 |
53 | * Improving **documentation on edge cases**, like documenting the behavior about when some attribute is not present or if we are allowed to pass nil to arguments.
54 | * Adding **support for OSX**. This should only need little adjustments, like getting rid of the `#import ` in the pch file, or replacing `UIColor` and `UIFont` classes with `NSColor` and `NSFont` (using macros to switch from one to another depending on the SDK), but that still requires some work and tests.
55 |
56 | > _Note: The original code of these categories comes from my old `OHAttributedLabel` pod, which is now deprecated as I don't have time to maintain it. As this previous implementation was based on CoreText and was not compatible (sometimes even crash) with UIKit/TextKit, I converted those categories to create this UIKit-compliant `NSAttributedString`, not related to CoreText and `OHAttributedLabel` anymore and that now work with latest versions of iOS/UIKit/TextKit._
57 |
58 | ## Licence
59 |
60 | This component is under the MIT Licence (See the `LICENSE` file).
61 |
--------------------------------------------------------------------------------
/README.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AliSoftware/OHAttributedStringAdditions/15d5d01c917ab60ac0be3ece523229a3de44a866/README.png
--------------------------------------------------------------------------------
/Source/NSAttributedString+OHAdditions.h:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | *
3 | * Copyright (c) 2010 Olivier Halligon
4 | *
5 | * Permission is hereby granted, free of charge, to any person obtaining a copy
6 | * of this software and associated documentation files (the "Software"), to deal
7 | * in the Software without restriction, including without limitation the rights
8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | * copies of the Software, and to permit persons to whom the Software is
10 | * furnished to do so, subject to the following conditions:
11 | *
12 | * The above copyright notice and this permission notice shall be included in
13 | * all copies or substantial portions of the Software.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | * THE SOFTWARE.
22 | *
23 | ******************************************************************************/
24 |
25 |
26 | #import
27 | #import
28 |
29 | /**
30 | * Convenience methods to create and manipulate `NSAttributedString` instances
31 | */
32 | @interface NSAttributedString (OHAdditions)
33 |
34 | /******************************************************************************/
35 | #pragma mark - Convenience Constructors
36 |
37 | /**
38 | * Build an NSAttributedString from a plain NSString
39 | *
40 | * @param string The string to build the attributed string from. May be `nil`.
41 | *
42 | * @return A new attributed string with the given string and default attributes
43 | *
44 | * @note This is a convenience method around alloc/initWithString but which
45 | * allows the parameter to be `nil`. If you pass `nil`, this method will
46 | * return an empty NSAttributedString.
47 | */
48 | + (instancetype)attributedStringWithString:(NSString*)string;
49 |
50 |
51 | /**
52 | * Build an NSAttributedString from a format and arguments, (like `stringWithFormat:`)
53 | *
54 | * @param format The format to build the attributed string from. You can use every
55 | * placeholder that you usually use in `-[NSString stringWithFormat:]`
56 | *
57 | * @return A new attributed string with the formatted string and default attributes
58 | *
59 | * @note This is a convenience method that calls `-[NSAttributedString initWithString:]`
60 | * with its parameter build from `-[NSString stringWithFormat:]`.
61 | */
62 | + (instancetype)attributedStringWithFormat:(NSString*)format, ... NS_FORMAT_FUNCTION(1,2);
63 |
64 | /**
65 | * Build an NSAttributedString from another NSAttributedString
66 | *
67 | * @param attrStr The attributed string to build the attributed string from.
68 | * May be `nil`.
69 | *
70 | * @return A new NSAttributedString with the same content as the original
71 | *
72 | * @note This method is generally only useful to build:
73 | *
74 | * - an NSAttributedString from an NSMutableAttributedString
75 | * - or an NSMutableAttributedString from an NSAttributedString
76 | */
77 | + (instancetype)attributedStringWithAttributedString:(NSAttributedString*)attrStr;
78 |
79 | /**
80 | * Build an NSAttributedString from HTML text.
81 | *
82 | * The HTML import mechanism is meant for implementing something like markdown
83 | * (that is, text styles, colors, and so on), not for general HTML import.
84 | *
85 | * @param htmlString The HTML string to build the attributed string from
86 | *
87 | * @return An NSAttributedString build from the HTML markup,
88 | * or `nil` if `htmlString` cannot be parsed.
89 | *
90 | * @note **Important**
91 | *
92 | * When this method is called from a thread other than the
93 | * main thread, the call will be dispatched synchronously on the main
94 | * thread (because the HTML importer needs to be executed on the main
95 | * thread only). Therefore, you should never call it on a thread that is
96 | * itself dispatched synchrnously from the main thread, or it will lead
97 | * to a deadlock. If you are in such a case, prefer using the
98 | * +loadHTMLString:completion: method instead.
99 | */
100 | + (instancetype)attributedStringWithHTML:(NSString*)htmlString;
101 |
102 | /**
103 | * Parse a string containing HTML markup into an NSAttributedString
104 | *
105 | * @param htmlString The HTML string to build the attributed string from
106 | * @param completion This block is called on the mainQueue upon completion
107 | * (when the HTML string has been parsed), returning asynchronously
108 | * the resulting `NSAttributedString` (or `nil` if it cannot be parsed).
109 | *
110 | * @note This method is dispatched asynchronously on the main thread (because
111 | * the HTML importer needs to be executed on the main thead only).
112 | */
113 | + (void)loadHTMLString:(NSString*)htmlString
114 | completion:(void(^)(NSAttributedString* attrString))completion;
115 |
116 | /******************************************************************************/
117 | #pragma mark - Size
118 |
119 | /**
120 | * Returns the size (in points) needed to draw the attributed string.
121 | *
122 | * @param maxSize The width and height constraints to apply when computing the
123 | * string’s bounding rectangle.
124 | *
125 | * @return the CGSize (width and height) required to draw the entire contents of the string.
126 | *
127 | * @note This method allows the string to be rendered in multiple lines if
128 | * needed, taking the attributedString's lineBreak mode configured in the
129 | * string's paragraph attributes into account).
130 | */
131 | - (CGSize)sizeConstrainedToSize:(CGSize)maxSize;
132 |
133 | /******************************************************************************/
134 | #pragma mark - Text Font
135 |
136 | /**
137 | * The default font used in an NSAttributedString when no specific font
138 | * attribute is defined.
139 | *
140 | * @return The "Helvetica" font with size 12.
141 | */
142 | + (UIFont*)defaultFont;
143 |
144 | /**
145 | * Returns the font applied at the given character index.
146 | *
147 | * @param index The character index for which to return the font
148 | * @param aRange If non-NULL:
149 | *
150 | * - If the font attribute exists at index, upon return `aRange`
151 | * contains a range over which the font applies.
152 | * - If the font attribute does not exist at index, upon return
153 | * `aRange` contains the range over which the font attribute does
154 | * not exist.
155 | *
156 | * The range isn’t necessarily the maximum range covered by the
157 | * font attribute.
158 | *
159 | * @return The value for the font attribute of the character at index `index`,
160 | * or `nil` if there is no font attribute.
161 | */
162 | - (UIFont*)fontAtIndex:(NSUInteger)index
163 | effectiveRange:(NSRangePointer)aRange;
164 |
165 | /**
166 | * Executes the Block for every font attribute runs in the specified range.
167 | *
168 | * If this method is sent to an instance of NSMutableAttributedString, mutation
169 | * (deletion, addition, or change) is allowed, as long as it is within the
170 | * range provided to the block; after a mutation, the enumeration continues
171 | * with the range immediately following the processed range, after the length
172 | * of the processed range is adjusted for the mutation. (The enumerator
173 | * basically assumes any change in length occurs in the specified range.)
174 | *
175 | * @param enumerationRange If non-NULL, contains the maximum range over which
176 | * the font attributes are enumerated, clipped to
177 | * enumerationRange.
178 | * @param block The Block to apply to ranges of the font attribute in the
179 | * attributed string. The Block takes three arguments:
180 | *
181 | * - `font`: The font of the enumerated text run.
182 | * - `range`: An NSRange indicating the run of the font.
183 | * - `stop`: A reference to a Boolean value. The block can set the
184 | * value to YES to stop further processing of the set.
185 | * The stop argument is an out-only argument. You should
186 | * only ever set this Boolean to YES within the Block.
187 | * @param includeUndefined If set to YES, this method will also call the block
188 | * for every range that does not have any font defined,
189 | * passing nil to the first argument of the block.
190 | */
191 | - (void)enumerateFontsInRange:(NSRange)enumerationRange
192 | includeUndefined:(BOOL)includeUndefined
193 | usingBlock:(void (^)(UIFont* font, NSRange range, BOOL *stop))block;
194 |
195 | /******************************************************************************/
196 | #pragma mark - Text Color
197 |
198 | /**
199 | * Returns the foreground text color applied at the given character index.
200 | *
201 | * @param index The character index for which to return the foreground color
202 | * @param aRange If non-NULL:
203 | *
204 | * - If the foreground color attribute exists at index, upon return
205 | * `aRange` contains a range over which the foreground color applies.
206 | * - If the foreground color attribute does not exist at index, upon
207 | * return `aRange` contains the range over which the foreground color
208 | * attribute does not exist.
209 | *
210 | * The range isn’t necessarily the maximum range covered by the
211 | * foreground color attribute.
212 | *
213 | * @return The value for the foreground color attribute of the character at
214 | * index `index`, or `nil` if there is no foreground color attribute.
215 | */
216 | - (UIColor*)textColorAtIndex:(NSUInteger)index
217 | effectiveRange:(NSRangePointer)aRange;
218 |
219 | /**
220 | * Returns the background text color applied at the given character index.
221 | *
222 | * @param index The character index for which to return the background color
223 | * @param aRange If non-NULL:
224 | *
225 | * - If the background color attribute exists at index, upon return
226 | * `aRange` contains a range over which the background color applies.
227 | * - If the background color attribute does not exist at index, upon
228 | * return `aRange` contains the range over which the background color
229 | * attribute does not exist.
230 | *
231 | * The range isn’t necessarily the maximum range covered by the
232 | * background color attribute.
233 | *
234 | * @return The value for the background color attribute of the character at
235 | * index `index`, or `nil` if there is no background color attribute.
236 | */
237 | - (UIColor*)textBackgroundColorAtIndex:(NSUInteger)index
238 | effectiveRange:(NSRangePointer)aRange;
239 |
240 | /******************************************************************************/
241 | #pragma mark - Text Underlining
242 |
243 | /**
244 | * Returns whether the underline attribute is applied at the given character
245 | * index.
246 | *
247 | * @param index The character index for which to return the underline state
248 | * @param aRange If non-NULL:
249 | *
250 | * - If the underline attribute exists at index, upon return `aRange`
251 | * contains a range over which the underline applies (with the same
252 | * underlineStyle).
253 | * - If the underline attribute does not exist at index, upon return
254 | * `aRange` contains the range over which the underline does not
255 | * exist.
256 | *
257 | * The range isn’t necessarily the maximum range covered by the
258 | * underline attribute.
259 | *
260 | * @return YES if the character at index `index` is underlined,
261 | * NO otherwise.
262 | *
263 | * @note This is a convenience method that calls the method
264 | * -textUnderlineStyleAtIndex:effectiveRange: and returns YES if the
265 | * result is other than NSUnderlineStyleNone.
266 | */
267 | - (BOOL)isTextUnderlinedAtIndex:(NSUInteger)index
268 | effectiveRange:(NSRangePointer)aRange;
269 |
270 | /**
271 | * Returns the underline style applied at the given character index.
272 | *
273 | * @param index The character index for which to return the underline style
274 | * @param aRange If non-NULL:
275 | *
276 | * - If the underline style attribute exists at index, upon return
277 | * `aRange` contains a range over which the underline style applies.
278 | * - If the underline style attribute does not exist at index, upon
279 | * return `aRange` contains the range over which the underline style
280 | * attribute does not exist.
281 | *
282 | * The range isn’t necessarily the maximum range covered by the
283 | * underline style attribute.
284 | *
285 | * @return The value for the underline style attribute of the character at
286 | * index `index`, or NSUnderlineStyleNone if there is no underline style
287 | * attribute.
288 | */
289 | - (NSUnderlineStyle)textUnderlineStyleAtIndex:(NSUInteger)index
290 | effectiveRange:(NSRangePointer)aRange;
291 |
292 | /**
293 | * Returns the underline color applied at the given character index.
294 | *
295 | * @param index The character index for which to return the underline color
296 | * @param aRange If non-NULL:
297 | *
298 | * - If the underline color attribute exists at index, upon return
299 | * `aRange` contains a range over which the underline color applies.
300 | * - If the underline color attribute does not exist at index, upon
301 | * return `aRange` contains the range over which the underline color
302 | * attribute does not exist.
303 | *
304 | * The range isn’t necessarily the maximum range covered by the
305 | * underline color attribute.
306 | *
307 | * @return The value for the underline color attribute of the character at
308 | * index `index`, or `nil` if there is no underline color attribute.
309 | */
310 | - (UIColor*)textUnderlineColorAtIndex:(NSUInteger)index
311 | effectiveRange:(NSRangePointer)aRange;
312 |
313 | /******************************************************************************/
314 | #pragma mark - Text Style & Traits
315 |
316 | /**
317 | * Returns whether the text is bold at the given character index.
318 | *
319 | * @param index The character index for which to return the bold state
320 | * @param aRange If non-NULL:
321 | *
322 | * - If a bold font attribute exists at index, upon return `aRange`
323 | * contains a range over which the bold font applies.
324 | * - If no font attribute exists at index, or the font attribute does
325 | * not have bold traits, upon return `aRange` contains the range over
326 | * which the non-bold font attribute apply.
327 | *
328 | * The range isn’t necessarily the maximum range covered by the
329 | * bold font attribute.
330 | *
331 | * @return YES if the character at index `index` is bold,
332 | * NO otherwise.
333 | *
334 | * @note This method actually fetch the font at the given index and the uses
335 | * NSFontDescriptor to check if the font has bold symbolic traits.
336 | */
337 | - (BOOL)isFontBoldAtIndex:(NSUInteger)index
338 | effectiveRange:(NSRangePointer)aRange;
339 |
340 | /**
341 | * Returns whether the text is in italics at the given character index.
342 | *
343 | * @param index The character index for which to return the italics state
344 | * @param aRange If non-NULL:
345 | *
346 | * - If an italics font attribute exists at index, upon return `aRange`
347 | * contains a range over which the italics font applies.
348 | * - If no font attribute exists at index, or the font attribute does
349 | * not have italics traits, upon return `aRange` contains the range
350 | * over which the non-italics font attribute apply.
351 | *
352 | * The range isn’t necessarily the maximum range covered by the
353 | * italics font attribute.
354 | *
355 | * @return YES if the character at index `index` is in italics,
356 | * NO otherwise.
357 | *
358 | * @note This method actually fetch the font at the given index and the uses
359 | * NSFontDescriptor to check if the font has italics symbolic traits.
360 | */
361 | - (BOOL)isFontItalicsAtIndex:(NSUInteger)index
362 | effectiveRange:(NSRangePointer)aRange;
363 |
364 | /******************************************************************************/
365 | #pragma mark - Link
366 |
367 | /**
368 | * Returns the URL attribute at the given character index.
369 | *
370 | * @param index The character index for which to return the URL
371 | * @param aRange If non-NULL:
372 | *
373 | * - If the URL attribute exists at index, upon return `aRange`
374 | * contains a range over which the URL applies.
375 | * - If the URL attribute does not exist at index, upon return `aRange`
376 | * contains the range over which the URL attribute does not exist.
377 | *
378 | * The range isn’t necessarily the maximum range covered by the
379 | * URL attribute.
380 | *
381 | * @return The value for the URL attribute of the character at index `index`,
382 | * or `nil` if there is no URL attribute.
383 | */
384 | - (NSURL*)URLAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange;
385 |
386 | /**
387 | * Executes the Block for every URL attribute runs in the specified range.
388 | *
389 | * If this method is sent to an instance of NSMutableAttributedString, mutation
390 | * (deletion, addition, or change) is allowed, as long as it is within the
391 | * range provided to the block; after a mutation, the enumeration continues
392 | * with the range immediately following the processed range, after the length
393 | * of the processed range is adjusted for the mutation. (The enumerator
394 | * basically assumes any change in length occurs in the specified range.)
395 | *
396 | * @param enumerationRange If non-NULL, contains the maximum range over which
397 | * the URL attributes are enumerated, clipped to
398 | * enumerationRange.
399 | * @param block The Block to apply to ranges of the URL attribute in the
400 | * attributed string. The Block takes three arguments:
401 | *
402 | * - `link`: The URL of the enumerated text run.
403 | * - `range`: An NSRange indicating the run of the URL.
404 | * - `stop`: A reference to a Boolean value. The block can set the
405 | * value to YES to stop further processing of the set.
406 | * The stop argument is an out-only argument. You should
407 | * only ever set this Boolean to YES within the Block.
408 | */
409 | - (void)enumerateURLsInRange:(NSRange)enumerationRange
410 | usingBlock:(void (^)(NSURL* link, NSRange range, BOOL *stop))block;
411 |
412 | /******************************************************************************/
413 | #pragma mark - Character Spacing
414 |
415 | /**
416 | * Returns the character spacing (kern attribute) applied at the given
417 | * character index.
418 | *
419 | * @param index The character index for which to return the character spacing
420 | * @param aRange If non-NULL:
421 | *
422 | * - If the kern attribute exists at index, upon return `aRange`
423 | * contains a range over which the kern attribute’s value applies.
424 | * - If the kern attribute does not exist at index, upon return
425 | * `aRange` contains the range over which the attribute does not
426 | * exist.
427 | *
428 | * The range isn’t necessarily the maximum range covered by the
429 | * kern attribute.
430 | *
431 | * @return The value for the kern attribute of the character at index `index`,
432 | * or 0 if there is no kern attribute (kerning disabled).
433 | *
434 | * @note For more info about typographical concepts, kerning and text layout,
435 | * see the [Text Programming Guide](https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/TypoFeatures/TextSystemFeatures.html#//apple_ref/doc/uid/TP40009542-CH6-51627-BBCCHIFF)
436 | */
437 | - (CGFloat)characterSpacingAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange;
438 |
439 | /******************************************************************************/
440 | #pragma mark - Subscript and Superscript
441 |
442 | /**
443 | * Returns the baseline offset applied at the given character index.
444 | *
445 | * @param index The character index for which to return the baseline offset
446 | * @param aRange If non-NULL:
447 | *
448 | * - If the baseline offset attribute exists at index, upon return
449 | * `aRange` contains a range over which the baseline offset applies.
450 | * - If the baseline offset attribute does not exist at index, upon
451 | * return `aRange` contains the range over which the baseline offset
452 | * attribute does not exist.
453 | *
454 | * The range isn’t necessarily the maximum range covered by the
455 | * baseline offset attribute.
456 | *
457 | * @return The value for the baseline offset of the character at index `index`,
458 | * or 0 if there is no baseline offset attribute.
459 | */
460 | - (CGFloat)baselineOffsetAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange;
461 |
462 | /******************************************************************************/
463 | #pragma mark - Paragraph Style
464 |
465 | /**
466 | * Returns the paragraph's text alignment applied at the given character index.
467 | *
468 | * @param index The character index for which to return the text aligment
469 | * @param aRange If non-NULL:
470 | *
471 | * - If the paragraph style attribute exists at index, upon return
472 | * `aRange` contains a range over which the paragraph style's text
473 | * alignment applies.
474 | * - If the paragraph style attribute does not exist at index, upon
475 | * return `aRange` contains the range over which the paragraph style
476 | * attribute does not exist.
477 | *
478 | * The range isn’t necessarily the maximum range covered by the
479 | * paragraph style attribute's text aligmnent.
480 | *
481 | * @return The value for the paragraph style's aligment attribute at the
482 | * character index `index`, or the default NSTextAlignmentLeft if there
483 | * is no paragraph style attribute.
484 | *
485 | * @note This is a convenience method that calls
486 | * -paragraphStyleAtIndex:effectiveRange: and returns the returned
487 | * object's aligbment property.
488 | */
489 | - (NSTextAlignment)textAlignmentAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange;
490 |
491 | /**
492 | * Returns the paragraph's line break mode applied at the given character
493 | * index.
494 | *
495 | * @param index The character index for which to return the line break mode
496 | * @param aRange If non-NULL:
497 | *
498 | * - If the paragraph style attribute exists at index, upon return
499 | * `aRange` contains a range over which the paragraph style's line
500 | * break mode applies.
501 | * - If the paragraph style attribute does not exist at index, upon
502 | * return `aRange` contains the range over which the paragraph style
503 | * attribute does not exist.
504 | *
505 | * The range isn’t necessarily the maximum range covered by the
506 | * paragraph style attribute's line break mode.
507 | *
508 | * @return The value for the paragraph style's line break mode attribute at the
509 | * character index `index`, or the default NSLineBreakByWordWrapping if
510 | * there is no paragraph style attribute.
511 | *
512 | * @note This is a convenience method that calls
513 | * -paragraphStyleAtIndex:effectiveRange: and returns the returned
514 | * object's lineBreakMode property.
515 | */
516 | - (NSLineBreakMode)lineBreakModeAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange;
517 |
518 | /**
519 | * Returns the paragraph style applied at the given character index.
520 | *
521 | * @param index The character index for which to return the paragraph style
522 | * @param aRange If non-NULL:
523 | *
524 | * - If the paragraph style attribute exists at index, upon return
525 | * `aRange` contains a range over which the paragraph style applies.
526 | * - If the paragraph style attribute does not exist at index, upon
527 | * return `aRange` contains the range over which the paragraph style
528 | * attribute does not exist.
529 | *
530 | * The range isn’t necessarily the maximum range covered by the
531 | * paragraph style attribute.
532 | *
533 | * @return The value for the paragraph style attribute at the character index
534 | * `index`, or `nil` if there is no paragraph style attribute.
535 | */
536 | - (NSParagraphStyle*)paragraphStyleAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange;
537 |
538 | /**
539 | * Executes the Block for every paragraph style attribute runs in the
540 | * specified range.
541 | *
542 | * If this method is sent to an instance of NSMutableAttributedString, mutation
543 | * (deletion, addition, or change) is allowed, as long as it is within the
544 | * range provided to the block; after a mutation, the enumeration continues
545 | * with the range immediately following the processed range, after the length
546 | * of the processed range is adjusted for the mutation. (The enumerator
547 | * basically assumes any change in length occurs in the specified range.)
548 | *
549 | * @param enumerationRange If non-NULL, contains the maximum range over which
550 | * the paragraph style attributes are enumerated,
551 | * clipped to enumerationRange.
552 | * @param block The Block to apply to ranges of the paragraph style attribute
553 | * in the attributed string. The Block takes three arguments:
554 | *
555 | * - `style`: The paragraph style of the enumerated text run.
556 | * - `range`: An NSRange indicating the run of the paragraph
557 | * style.
558 | * - `stop`: A reference to a Boolean value. The block can set the
559 | * value to YES to stop further processing of the set.
560 | * The stop argument is an out-only argument. You should
561 | * only ever set this Boolean to YES within the Block.
562 | * @param includeUndefined If set to YES, this method will also call the block
563 | * for every range that does not have any paragraph style
564 | * defined, passing nil to the first argument of the block.
565 | *
566 | */
567 | - (void)enumerateParagraphStylesInRange:(NSRange)enumerationRange
568 | includeUndefined:(BOOL)includeUndefined
569 | usingBlock:(void (^)(NSParagraphStyle* style, NSRange range, BOOL *stop))block;
570 |
571 | @end
572 |
573 |
574 |
575 |
--------------------------------------------------------------------------------
/Source/NSAttributedString+OHAdditions.m:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * This software is under the MIT License quoted below:
3 | *******************************************************************************
4 | *
5 | * Copyright (c) 2010 Olivier Halligon
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in
15 | * all copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | * THE SOFTWARE.
24 | *
25 | ******************************************************************************/
26 |
27 |
28 | #import "NSAttributedString+OHAdditions.h"
29 |
30 | @implementation NSAttributedString (OHAdditions)
31 |
32 | /******************************************************************************/
33 | #pragma mark - Convenience Constructors
34 |
35 | + (instancetype)attributedStringWithString:(NSString*)string
36 | {
37 | if (string)
38 | {
39 | return [[self alloc] initWithString:string];
40 | }
41 | else
42 | {
43 | return [self new];
44 | }
45 | }
46 |
47 | + (instancetype)attributedStringWithFormat:(NSString*)format, ...
48 | {
49 | va_list args;
50 | va_start(args, format);
51 | NSString* string = [[NSString alloc] initWithFormat:format arguments:args];
52 | va_end(args);
53 | return [[self alloc] initWithString:string];
54 | }
55 |
56 | + (instancetype)attributedStringWithAttributedString:(NSAttributedString*)attrStr
57 | {
58 | if (attrStr)
59 | {
60 | return [[self alloc] initWithAttributedString:attrStr];
61 | }
62 | else
63 | {
64 | return [self new];
65 | }
66 | }
67 |
68 | + (instancetype)attributedStringWithHTML:(NSString*)htmlString
69 | {
70 | NSData* htmlData = [htmlString dataUsingEncoding:NSUTF8StringEncoding];
71 | if (htmlData)
72 | {
73 | NSDictionary* options = @{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
74 | NSCharacterEncodingDocumentAttribute: @(NSUTF8StringEncoding)};
75 | __block id attributedString = nil;
76 | dispatch_block_t block = ^{
77 | attributedString = [[self alloc] initWithData:htmlData
78 | options:options
79 | documentAttributes:nil
80 | error:NULL];
81 | };
82 |
83 | if ([NSThread isMainThread])
84 | {
85 | block();
86 | }
87 | else
88 | {
89 | // See Apple Doc: HTML importer should always be called on the main thread
90 | dispatch_sync(dispatch_get_main_queue(), block);
91 | }
92 |
93 | return attributedString;
94 | }
95 | else
96 | {
97 | return nil;
98 | }
99 | }
100 |
101 | + (void)loadHTMLString:(NSString*)htmlString
102 | completion:(void(^)(NSAttributedString* attrString))completion
103 | {
104 | if (!completion) return;
105 |
106 | NSData* htmlData = [htmlString dataUsingEncoding:NSUTF8StringEncoding];
107 | if (htmlData)
108 | {
109 | NSDictionary* options = @{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
110 | NSCharacterEncodingDocumentAttribute: @(NSUTF8StringEncoding)};
111 | dispatch_async(dispatch_get_main_queue(), ^{
112 | NSAttributedString* attributedString = [[self alloc] initWithData:htmlData
113 | options:options
114 | documentAttributes:nil
115 | error:NULL];
116 | completion(attributedString);
117 | });
118 | }
119 | else
120 | {
121 | dispatch_async(dispatch_get_main_queue(), ^{
122 | completion(nil);
123 | });
124 | }
125 | }
126 |
127 | /******************************************************************************/
128 | #pragma mark - Size
129 |
130 | - (CGSize)sizeConstrainedToSize:(CGSize)maxSize
131 | {
132 | // Use NSStringDrawingUsesLineFragmentOrigin to compute bounds of multi-line strings (see Apple doc)
133 | CGRect bounds = [self boundingRectWithSize:maxSize
134 | options:NSStringDrawingUsesLineFragmentOrigin
135 | context:nil];
136 |
137 | // We need to ceil the returned values (see Apple doc)
138 | return CGSizeMake((CGFloat)ceil((double)bounds.size.width),
139 | (CGFloat)ceil((double)bounds.size.height) );
140 | }
141 |
142 | /******************************************************************************/
143 | #pragma mark - Text Font
144 |
145 | + (UIFont*)defaultFont
146 | {
147 | // The default font used for NSAttributedString according to the doc
148 | return [UIFont fontWithName:@"Helvetica" size:12];
149 | }
150 |
151 | - (UIFont*)fontAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange
152 | {
153 | return [self attribute:NSFontAttributeName atIndex:index effectiveRange:aRange];
154 | }
155 |
156 | - (void)enumerateFontsInRange:(NSRange)enumerationRange
157 | includeUndefined:(BOOL)includeUndefined
158 | usingBlock:(void (^)(UIFont*, NSRange, BOOL *))block
159 | {
160 | NSParameterAssert(block);
161 |
162 | [self enumerateAttribute:NSFontAttributeName
163 | inRange:enumerationRange
164 | options:0
165 | usingBlock:^(id font, NSRange aRange, BOOL *stop)
166 | {
167 | if (font || includeUndefined) block(font, aRange, stop);
168 | }];
169 | }
170 |
171 | /******************************************************************************/
172 | #pragma mark - Text Color
173 |
174 | - (UIColor*)textColorAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange
175 | {
176 | return [self attribute:NSForegroundColorAttributeName atIndex:index effectiveRange:aRange];
177 | }
178 |
179 | - (UIColor*)textBackgroundColorAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange
180 | {
181 | return [self attribute:NSBackgroundColorAttributeName atIndex:index effectiveRange:aRange];
182 | }
183 |
184 | /******************************************************************************/
185 | #pragma mark - Text Underlining
186 |
187 | - (BOOL)isTextUnderlinedAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange
188 | {
189 | NSUnderlineStyle underlineStyle = [self textUnderlineStyleAtIndex:index effectiveRange:aRange];
190 | return underlineStyle != NSUnderlineStyleNone;
191 | }
192 |
193 | - (NSUnderlineStyle)textUnderlineStyleAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange
194 | {
195 | NSNumber* attr = [self attribute:NSUnderlineStyleAttributeName atIndex:index effectiveRange:aRange];
196 | return [attr integerValue];
197 | }
198 |
199 | - (UIColor*)textUnderlineColorAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange
200 | {
201 | return [self attribute:NSUnderlineColorAttributeName atIndex:index effectiveRange:aRange];
202 | }
203 |
204 | /******************************************************************************/
205 | #pragma mark - Text Style & Traits
206 |
207 | - (BOOL)isFontBoldAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange
208 | {
209 | UIFont* font = [self fontAtIndex:index effectiveRange:aRange];
210 | UIFontDescriptorSymbolicTraits symTraits = font.fontDescriptor.symbolicTraits;
211 | return (symTraits & UIFontDescriptorTraitBold) != 0;
212 | }
213 |
214 | - (BOOL)isFontItalicsAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange
215 | {
216 | UIFont* font = [self fontAtIndex:index effectiveRange:aRange];
217 | UIFontDescriptorSymbolicTraits symTraits = font.fontDescriptor.symbolicTraits;
218 | return (symTraits & UIFontDescriptorTraitItalic) != 0;
219 | }
220 |
221 | /******************************************************************************/
222 | #pragma mark - Links
223 |
224 | - (NSURL*)URLAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange
225 | {
226 | return [self attribute:NSLinkAttributeName atIndex:index effectiveRange:aRange];
227 | }
228 |
229 | - (void)enumerateURLsInRange:(NSRange)enumerationRange
230 | usingBlock:(void (^)(NSURL*, NSRange, BOOL *))block
231 | {
232 | NSParameterAssert(block);
233 |
234 | [self enumerateAttribute:NSLinkAttributeName
235 | inRange:enumerationRange
236 | options:0
237 | usingBlock:^(id url, NSRange range, BOOL *stop)
238 | {
239 | if (url) block(url, range, stop);
240 | }];
241 | }
242 |
243 | /******************************************************************************/
244 | #pragma mark - Character Spacing
245 |
246 | - (CGFloat)characterSpacingAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange
247 | {
248 | return [[self attribute:NSKernAttributeName atIndex:index effectiveRange:aRange] floatValue];
249 | }
250 |
251 | /******************************************************************************/
252 | #pragma mark - Subscript and Superscript
253 |
254 | - (CGFloat)baselineOffsetAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange
255 | {
256 | return [[self attribute:NSBaselineOffsetAttributeName atIndex:index effectiveRange:aRange] floatValue];
257 | }
258 |
259 | /******************************************************************************/
260 | #pragma mark - Paragraph Style
261 |
262 | - (NSTextAlignment)textAlignmentAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange
263 | {
264 | NSParagraphStyle* style = [self paragraphStyleAtIndex:index effectiveRange:aRange];
265 | return style.alignment;
266 | }
267 |
268 | - (NSLineBreakMode)lineBreakModeAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange
269 | {
270 | NSParagraphStyle* style = [self paragraphStyleAtIndex:index effectiveRange:aRange];
271 | return style.lineBreakMode;
272 | }
273 |
274 | - (NSParagraphStyle*)paragraphStyleAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange
275 | {
276 | return [self attribute:NSParagraphStyleAttributeName atIndex:index effectiveRange:aRange];
277 | }
278 |
279 | - (void)enumerateParagraphStylesInRange:(NSRange)enumerationRange
280 | includeUndefined:(BOOL)includeUndefined
281 | usingBlock:(void (^)(NSParagraphStyle*, NSRange, BOOL *))block
282 | {
283 | NSParameterAssert(block);
284 |
285 | [self enumerateAttribute:NSParagraphStyleAttributeName
286 | inRange:enumerationRange
287 | options:0
288 | usingBlock:^(id style, NSRange aRange, BOOL *stop)
289 | {
290 | if (style || includeUndefined) block(style, aRange, stop);
291 | }];
292 | }
293 |
294 | @end
295 |
296 |
297 |
298 |
299 |
--------------------------------------------------------------------------------
/Source/NSMutableAttributedString+OHAdditions.h:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | *
3 | * Copyright (c) 2010 Olivier Halligon
4 | *
5 | * Permission is hereby granted, free of charge, to any person obtaining a copy
6 | * of this software and associated documentation files (the "Software"), to deal
7 | * in the Software without restriction, including without limitation the rights
8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | * copies of the Software, and to permit persons to whom the Software is
10 | * furnished to do so, subject to the following conditions:
11 | *
12 | * The above copyright notice and this permission notice shall be included in
13 | * all copies or substantial portions of the Software.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | * THE SOFTWARE.
22 | *
23 | ******************************************************************************/
24 |
25 |
26 | #import
27 | #import
28 |
29 | /**
30 | * Convenience methods to modify `NSMutableAttributedString` instances
31 | */
32 | @interface NSMutableAttributedString (OHAdditions)
33 |
34 | /******************************************************************************/
35 | #pragma mark - Text Font
36 |
37 | /**
38 | * Set the font for the whole attributed string.
39 | *
40 | * The font of the whole attributed string will be overridden.
41 | *
42 | * @param font The font to apply
43 | *
44 | * @note You can take advantage of `UIFont+OHAdditions` category to create a
45 | * font with a given family, size and traits.
46 | */
47 | - (void)setFont:(UIFont*)font;
48 |
49 | /**
50 | * Set the font for the given range of characters.
51 | *
52 | * @param font The font to apply
53 | * @param range The range of characters to which the font should apply.
54 | *
55 | * @note You can take advantage of `UIFont+OHAdditions` category to create a
56 | * font with a given family, size and traits.
57 | */
58 | - (void)setFont:(UIFont*)font range:(NSRange)range;
59 |
60 | /******************************************************************************/
61 | #pragma mark - Text Color
62 |
63 | /**
64 | * Set the foreground text color for the whole attributed string.
65 | *
66 | * @param color The foreground color to apply
67 | */
68 | - (void)setTextColor:(UIColor*)color;
69 |
70 | /**
71 | * Set the foreground text color for the given range of characters.
72 | *
73 | * @param color The foreground color to apply
74 | * @param range The range of characters to which the color should apply.
75 | */
76 | - (void)setTextColor:(UIColor*)color range:(NSRange)range;
77 |
78 | /**
79 | * Set the background text color for the whole attributed string.
80 | *
81 | * @param color The background color to apply
82 | */
83 | - (void)setTextBackgroundColor:(UIColor*)color;
84 |
85 | /**
86 | * Set the background text color for the given range of characters.
87 | *
88 | * @param color The background color to apply
89 | * @param range The range of characters to which the color should apply.
90 | */
91 | - (void)setTextBackgroundColor:(UIColor*)color range:(NSRange)range;
92 |
93 | /******************************************************************************/
94 | #pragma mark - Text Underlining
95 |
96 | /**
97 | * Set the underline for the whole attributed string.
98 | *
99 | * @param underlined `YES` if you want the text to be underlined, `NO` otherwise.
100 | *
101 | * @note This is a convenience method that ends up calling
102 | * `setTextUnderlineStyle:range:` with the value
103 | * `(NSUnderlineStyleSingle|NSUnderlinePatternSolid)` if underlined is
104 | * `YES`, `NSUnderlineStyleNone` if underlined is `NO`.
105 | */
106 | - (void)setTextUnderlined:(BOOL)underlined;
107 |
108 | /**
109 | * Set the underline for the given range of characters.
110 | *
111 | * @param underlined `YES` if you want the text to be underlined, `NO` otherwise.
112 | * @param range The range of characters to which the underline should apply.
113 | *
114 | * @note This is a convenience method that ends up calling
115 | * `setTextUnderlineStyle:range:` with the value
116 | * `(NSUnderlineStyleSingle|NSUnderlinePatternSolid)` if underlined is
117 | * `YES`, `NSUnderlineStyleNone` if underlined is `NO`.
118 | */
119 | - (void)setTextUnderlined:(BOOL)underlined range:(NSRange)range;
120 |
121 | /**
122 | * Set the underline style for the given range of characters.
123 | *
124 | * @param style The underline style mask, like
125 | * `NSUnderlineStyleSingle|NSUnderlinePatternDot` or
126 | * `NSUnderlineStyleDouble|NSUnderlinePatternSolid` for example.
127 | * @param range The range of characters to which the underline style should
128 | * apply.
129 | */
130 | - (void)setTextUnderlineStyle:(NSUnderlineStyle)style range:(NSRange)range;
131 |
132 | /**
133 | * Set the underline color for the whole attributed string
134 | *
135 | * @param color The color to apply to the underlining. If nil, the underlining
136 | * will be the same color as the text foreground color.
137 | */
138 | - (void)setTextUnderlineColor:(UIColor*)color;
139 |
140 | /**
141 | * Set the underline color for the given range of characters.
142 | *
143 | * @param color The color to apply to the underlining. If nil, the underlining
144 | * will be the same color as the text foreground color.
145 | *
146 | * @param range The range of characters to which the underline color should
147 | * apply.
148 | */
149 | - (void)setTextUnderlineColor:(UIColor*)color range:(NSRange)range;
150 |
151 | /******************************************************************************/
152 | #pragma mark - Text Style & Traits
153 |
154 | /**
155 | * Enumerates on every font in the attributed string, allowing you to
156 | * easily give new font symbolic traits to each font enumerated.
157 | *
158 | * This method is useful to easily change font traits of a whole attributed
159 | * string without changing/overridding the font family of each font run. For
160 | * example, you can use this method to add or remove the
161 | * `UIFontDescriptorTraitItalic``, `UIFontDescriptorTraitBold`,
162 | * `UIFontDescriptorTraitExpanded` and/or `UIFontDescriptorTraitCondensed`
163 | * traits of every enumerated font.
164 | *
165 | * @param block A block that takes the enumerated font symbolic traits as
166 | * only parameter and returns the new symbolic font traits to
167 | * apply.
168 | *
169 | * @note This method also calls the enumeration block for ranges where no font
170 | * is explicitly defined (no NSFontAttribute set); in such case, the
171 | * traits of the [NSAttributedString defaultFont] are passed as first
172 | * parameter of the block. The font attribute is then explicitly
173 | * set (even if it did not exist before), to be able to change the font
174 | * traits for those ranges as well instead of keeping the default.
175 | */
176 | - (void)changeFontTraitsWithBlock:(UIFontDescriptorSymbolicTraits(^)(UIFontDescriptorSymbolicTraits currentTraits, NSRange aRange))block;
177 |
178 | /**
179 | * Enumerates on every font in the given range of characters, allowing you to
180 | * easily give new font symbolic traits to each font enumerated.
181 | *
182 | * This method is useful to easily change font traits of a whole range without
183 | * changing/overridding the font family of each font run. For example, you can
184 | * use this method to add or remove the `UIFontDescriptorTraitItalic`,
185 | * `UIFontDescriptorTraitBold`, `UIFontDescriptorTraitExpanded` and/or
186 | * `UIFontDescriptorTraitCondensed` traits of every enumerated font.
187 | *
188 | * @param range The range of characters to which the traits should be
189 | * enumerated
190 | * @param block A block that takes the enumerated font symbolic traits as
191 | * only parameter and returns the new symbolic font traits to
192 | * apply.
193 | *
194 | * @note This method also calls the enumeration block for ranges where no font
195 | * is explicitly defined (no NSFontAttribute set); in such case, the
196 | * traits of the [NSAttributedString defaultFont] are passed as first
197 | * parameter of the block. The font attribute is then explicitly
198 | * set (even if it did not exist before), to be able to change the font
199 | * traits for those ranges as well instead of keeping the default.
200 | */
201 | - (void)changeFontTraitsInRange:(NSRange)range
202 | withBlock:(UIFontDescriptorSymbolicTraits(^)(UIFontDescriptorSymbolicTraits currentTraits, NSRange aRange))block;
203 |
204 | /**
205 | * Change every fonts of the attributed string to their bold variant.
206 | *
207 | * @param isBold `YES` if you want to use bold font variants, `NO` if you want to
208 | * use non-bold font variants.
209 | *
210 | * @note This is a convenience method that calls
211 | * `changeFontTraitsInRange:withBlock:` with a block that adds (`isBold`
212 | * = `YES`) or remove (isBold = `NO`) the `UIFontDescriptorTraitBold`
213 | * trait to each enumerated font.
214 | */
215 | - (void)setFontBold:(BOOL)isBold;
216 |
217 | /**
218 | * Change the font of the given range of characters to its bold variant.
219 | *
220 | * @param isBold `YES` if you want to use bold font variants, `NO` if you want to
221 | * use non-bold font variants.
222 | * @param range The range of characters to which the bold font should apply.
223 | *
224 | * @note This is a convenience method that calls
225 | * `changeFontTraitsInRange:withBlock:` with a block that adds (`isBold`
226 | * = `YES`) or remove (isBold = `NO`) the `UIFontDescriptorTraitBold`
227 | * trait to each enumerated font.
228 | */
229 | - (void)setFontBold:(BOOL)isBold range:(NSRange)range;
230 |
231 | /**
232 | * Change every fonts of the attributed string to their italics variant.
233 | *
234 | * @param isItalics `YES` if you want to use italics font variants,
235 | * `NO` if you want to use non-italics font variants.
236 | *
237 | * @note This is a convenience method that calls
238 | * `changeFontTraitsInRange:withBlock:` with a block that adds (
239 | * `isItalics` = `YES`) or remove (isItalics = `NO`) the
240 | * `UIFontDescriptorTraitItalic` trait to each enumerated font.
241 | */
242 | - (void)setFontItalics:(BOOL)isItalics;
243 |
244 | /**
245 | * Change the font of the given range of characters to its italics variant.
246 | *
247 | * @param isItalics `YES` if you want to use italics font variants,
248 | * `NO` if you want to use non-italics font variants.
249 | * @param range The range of characters to which the italics font should apply.
250 | *
251 | * @note This is a convenience method that calls
252 | * changeFontTraitsInRange:withBlock: with a block that adds (isItalics =
253 | * `YES`) or remove (`isItalics` = `NO`) the
254 | * `UIFontDescriptorTraitItalic` trait to each enumerated font.
255 | */
256 | - (void)setFontItalics:(BOOL)isItalics range:(NSRange)range;
257 |
258 | /******************************************************************************/
259 | #pragma mark - Link
260 |
261 | /**
262 | * Add an URL link to the given range of characters.
263 | *
264 | * @param linkURL the URL to apply
265 | * @param range The range of characters to which the URL should apply.
266 | */
267 | - (void)setURL:(NSURL*)linkURL range:(NSRange)range;
268 |
269 | /******************************************************************************/
270 | #pragma mark - Character Spacing
271 |
272 | /**
273 | * Set the character spacing (kern attribute) of the whole attributed string
274 | *
275 | * @param characterSpacing The character spacing. This value specifies the
276 | * number of points by which to adjust kern-pair
277 | * characters. A value of 0 disables kerning.
278 | *
279 | * @note For more info about typographical concepts, kerning and text layout,
280 | * see the [Text Programming Guide](https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/TypoFeatures/TextSystemFeatures.html#//apple_ref/doc/uid/TP40009542-CH6-51627-BBCCHIFF)
281 | */
282 | - (void)setCharacterSpacing:(CGFloat)characterSpacing;
283 |
284 | /**
285 | * Set the character spacing (kern attribute) of the given range of characters.
286 | *
287 | * @param characterSpacing The character spacing. This value specifies the
288 | * number of points by which to adjust kern-pair
289 | * characters. A value of 0 disables kerning.
290 | * @param range The range of characters to which the character spacing
291 | * (kerning) should apply.
292 | *
293 | * @note For more info about typographical concepts, kerning and text layout,
294 | * see the [Text Programming Guide](https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/TypoFeatures/TextSystemFeatures.html#//apple_ref/doc/uid/TP40009542-CH6-51627-BBCCHIFF)
295 | */
296 | - (void)setCharacterSpacing:(CGFloat)characterSpacing range:(NSRange)range;
297 |
298 | /******************************************************************************/
299 | #pragma mark - Subscript and Superscript
300 |
301 | /**
302 | * Set the baseline offset of the whole attributed string.
303 | *
304 | * @param offset The character's offset from the baseline, in points.
305 | */
306 | - (void)setBaselineOffset:(CGFloat)offset;
307 |
308 | /**
309 | * Set the baseline offset of the given range of characters.
310 | *
311 | * @param offset The character's offset from the baseline, in points.
312 | * @param range The range of characters to which the baseline offset should
313 | * apply.
314 | */
315 | - (void)setBaselineOffset:(CGFloat)offset range:(NSRange)range;
316 |
317 | /**
318 | * Set the given range of characters to be superscripted, meaning that
319 | * they have a positive offset above the baseline and have a font half the
320 | * current font size.
321 | *
322 | * @param range The range of characters to which the superscript should apply.
323 | *
324 | * @note This is a convenient method that calls -setBaselineOffset:range:
325 | * using a positive offset of half of the pointSize of the font at the
326 | * range's start location
327 | */
328 | - (void)setSuperscriptForRange:(NSRange)range;
329 |
330 | /**
331 | * Set the given range of characters to be subscripted, meaning that
332 | * they have a negative offset below the baseline and have a font half the
333 | * current font size.
334 | *
335 | * @param range The range of characters to which the subscript should apply.
336 | *
337 | * @note This is a convenient method that calls -setBaselineOffset:range:
338 | * using a negative offset of half of the pointSize of the font at the
339 | * range's start location
340 | */
341 | - (void)setSubscriptForRange:(NSRange)range;
342 |
343 | /******************************************************************************/
344 | #pragma mark - Paragraph Style
345 |
346 | /**
347 | * Set the paragraph's text alignment for the whole attributed string.
348 | *
349 | * @param alignment The paragraph's text alignment to apply
350 | */
351 | - (void)setTextAlignment:(NSTextAlignment)alignment;
352 |
353 | /**
354 | * Set the paragraph's text alignment for the given range of characters.
355 | *
356 | * @param alignment The paragraph's text alignment to apply
357 | * @param range The range of characters to which the text alignment should
358 | * apply.
359 | */
360 | - (void)setTextAlignment:(NSTextAlignment)alignment range:(NSRange)range;
361 |
362 | /**
363 | * Set the paragraph's line break mode for the whole attributed string.
364 | *
365 | * @param lineBreakMode The paragraph's line break mode to apply
366 | */
367 | - (void)setLineBreakMode:(NSLineBreakMode)lineBreakMode;
368 |
369 | /**
370 | * Set the paragraph's line break mode for the given range of characters.
371 | *
372 | * @param lineBreakMode The paragraph's line break mode to apply
373 | * @param range The range of characters to which the line break mode should
374 | * apply.
375 | */
376 | - (void)setLineBreakMode:(NSLineBreakMode)lineBreakMode range:(NSRange)range;
377 |
378 | /**
379 | * This methods allows you to change only certain Paragraph Styles properties
380 | * without changing the others (for example changing the firstLineHeadIndent
381 | * or line spacing without overriding the textAlignment).
382 | *
383 | * It is useful as NSParagraphStyle objects carry multiple text styles in only
384 | * one common attribute, but you sometimes want to change only one of the text
385 | * style without altering the others.
386 | *
387 | * @param block A block that takes the mutable paragraph style as the only
388 | * parameter, allowing you to change its properties.
389 | *
390 | * @note This method actually enumerate all paragraph styles of your
391 | * attributed string, create a mutable copy of the NSParagraphStyle to
392 | * pass it to the block, then reapply the modified paragraph style to
393 | * the original range.
394 | *
395 | * @note This method also calls the enumeration block for ranges where no
396 | * paragraph style is explicitly defined (no NSParagraphStyleAttribute
397 | * set); in such case, the [NSParagraphStyle defaultStyle] is passed as
398 | * first parameter of the block. The paragraph style attribute is then
399 | * explicitly set (even if it did not exist before), to be able to change
400 | * the paragraph style for those ranges as well instead of keeping the default
401 | */
402 | - (void)changeParagraphStylesWithBlock:(void(^)(NSMutableParagraphStyle* currentStyle, NSRange aRange))block;
403 |
404 | /**
405 | * This methods allows you to change only certain Paragraph Styles properties
406 | * without changing the others (for example changing the firstLineHeadIndent
407 | * or line spacing without overriding the textAlignment).
408 | *
409 | * It is useful as NSParagraphStyle objects carry multiple text styles in only
410 | * one common attribute, but you sometimes want to change only one of the text
411 | * style without altering the others.
412 | *
413 | * @param range The range of characters to which the paragraph style
414 | * modifications should apply.
415 | * @param block A block that takes the mutable paragraph style as the only
416 | * parameter, allowing you to change its properties.
417 | *
418 | * @note This method actually enumerate all paragraph styles in the given
419 | * range of your attributed string, create a mutable copy of the
420 | * NSParagraphStyle to pass it to the block, then reapply the modified
421 | * paragraph style to the original range.
422 | *
423 | * @note This method also calls the enumeration block for ranges where no
424 | * paragraph style is explicitly defined (no NSParagraphStyleAttribute
425 | * set); in such case, the [NSParagraphStyle defaultStyle] is passed as
426 | * first parameter of the block. The paragraph style attribute is then
427 | * explicitly set (even if it did not exist before), to be able to change
428 | * the paragraph style for those ranges as well instead of keeping the default
429 | */
430 | - (void)changeParagraphStylesInRange:(NSRange)range
431 | withBlock:(void(^)(NSMutableParagraphStyle* currentStyle, NSRange aRange))block;
432 |
433 | /**
434 | * Override the Paragraph Styles, dropping the ones previously set if any.
435 | * Be aware that this will override the text alignment, linebreakmode, and all
436 | * other paragraph styles with the new values.
437 | *
438 | * @param style The new paragraph style to apply
439 | */
440 | - (void)setParagraphStyle:(NSParagraphStyle *)style;
441 |
442 | /**
443 | * Override the Paragraph Styles of the given range of characters, dropping
444 | * the ones previously set if any.
445 | * Be aware that this will override the text alignment, linebreakmode, and all
446 | * other paragraph styles in the given range with the new values.
447 | *
448 | * @param style The new paragraph style to apply
449 | * @param range The range of characters to which the paragraphe style should
450 | * apply.
451 | */
452 | - (void)setParagraphStyle:(NSParagraphStyle*)style range:(NSRange)range;
453 |
454 | @end
455 |
--------------------------------------------------------------------------------
/Source/NSMutableAttributedString+OHAdditions.m:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * This software is under the MIT License quoted below:
3 | *******************************************************************************
4 | *
5 | * Copyright (c) 2010 Olivier Halligon
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in
15 | * all copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | * THE SOFTWARE.
24 | *
25 | ******************************************************************************/
26 |
27 |
28 | #import "NSMutableAttributedString+OHAdditions.h"
29 | #import "NSAttributedString+OHAdditions.h"
30 | #import "UIFont+OHAdditions.h"
31 |
32 | @implementation NSMutableAttributedString (OHAdditions)
33 |
34 | /******************************************************************************/
35 | #pragma mark - Text Font
36 |
37 | - (void)setFont:(UIFont*)font
38 | {
39 | [self setFont:font range:NSMakeRange(0, self.length)];
40 | }
41 |
42 | - (void)setFont:(UIFont*)font range:(NSRange)range
43 | {
44 | if (font)
45 | {
46 | [self removeAttribute:NSFontAttributeName range:range]; // Work around for Apple leak
47 | [self addAttribute:NSFontAttributeName value:(id)font range:range];
48 | }
49 | }
50 |
51 |
52 | /******************************************************************************/
53 | #pragma mark - Text Color
54 |
55 | - (void)setTextColor:(UIColor*)color
56 | {
57 | [self setTextColor:color range:NSMakeRange(0,self.length)];
58 | }
59 |
60 | - (void)setTextColor:(UIColor*)color range:(NSRange)range
61 | {
62 | [self removeAttribute:NSForegroundColorAttributeName range:range]; // Work around for Apple leak
63 | [self addAttribute:NSForegroundColorAttributeName value:(id)color range:range];
64 | }
65 |
66 | - (void)setTextBackgroundColor:(UIColor*)color
67 | {
68 | [self setTextBackgroundColor:color range:NSMakeRange(0, self.length)];
69 | }
70 |
71 | - (void)setTextBackgroundColor:(UIColor*)color range:(NSRange)range
72 | {
73 | [self removeAttribute:NSBackgroundColorAttributeName range:range]; // Work around for Apple leak
74 | [self addAttribute:NSBackgroundColorAttributeName value:(id)color range:range];
75 | }
76 |
77 | /******************************************************************************/
78 | #pragma mark - Text Underlining
79 |
80 | - (void)setTextUnderlined:(BOOL)underlined
81 | {
82 | [self setTextUnderlined:underlined range:NSMakeRange(0,self.length)];
83 | }
84 |
85 | - (void)setTextUnderlined:(BOOL)underlined range:(NSRange)range
86 | {
87 | NSUnderlineStyle style = underlined ? (NSUnderlineStyleSingle|NSUnderlinePatternSolid) : NSUnderlineStyleNone;
88 | [self setTextUnderlineStyle:style range:range];
89 | }
90 |
91 | - (void)setTextUnderlineStyle:(NSUnderlineStyle)style range:(NSRange)range
92 | {
93 | [self removeAttribute:NSUnderlineStyleAttributeName range:range]; // Work around for Apple leak
94 | [self addAttribute:NSUnderlineStyleAttributeName value:@(style) range:range];
95 | }
96 |
97 | - (void)setTextUnderlineColor:(UIColor*)color
98 | {
99 | [self setTextUnderlineColor:color range:NSMakeRange(0, self.length)];
100 | }
101 |
102 | - (void)setTextUnderlineColor:(UIColor*)color range:(NSRange)range
103 | {
104 | [self removeAttribute:NSUnderlineColorAttributeName range:range]; // Work around for Apple leak
105 | [self addAttribute:NSUnderlineColorAttributeName value:color range:range];
106 | }
107 |
108 | /******************************************************************************/
109 | #pragma mark - Text Style & Traits
110 |
111 | - (void)changeFontTraitsWithBlock:(UIFontDescriptorSymbolicTraits(^)(UIFontDescriptorSymbolicTraits, NSRange))block
112 | {
113 | [self changeFontTraitsInRange:NSMakeRange(0, self.length)
114 | withBlock:block];
115 | }
116 |
117 | - (void)changeFontTraitsInRange:(NSRange)range
118 | withBlock:(UIFontDescriptorSymbolicTraits(^)(UIFontDescriptorSymbolicTraits, NSRange))block
119 | {
120 | NSParameterAssert(block);
121 | [self beginEditing];
122 | [self enumerateFontsInRange:range
123 | includeUndefined:YES
124 | usingBlock:^(UIFont* font, NSRange aRange, BOOL *stop)
125 | {
126 | if (!font) font = [[self class] defaultFont];
127 | UIFontDescriptorSymbolicTraits currentTraits = font.symbolicTraits;
128 | UIFontDescriptorSymbolicTraits newTraits = block(currentTraits, aRange);
129 | UIFont* newFont = [font fontWithSymbolicTraits:newTraits];
130 | [self setFont:newFont range:aRange];
131 | }];
132 | [self endEditing];
133 | }
134 |
135 | - (void)setFontBold:(BOOL)isBold
136 | {
137 | [self setFontBold:isBold range:NSMakeRange(0, self.length)];
138 | }
139 |
140 | // TODO: Check out the effect of the NSStrokeWidthAttributeName attribute
141 | // to see if we can also fake bold fonts by increasing the font weight
142 | - (void)setFontBold:(BOOL)isBold range:(NSRange)range
143 | {
144 | [self changeFontTraitsInRange:range withBlock:^UIFontDescriptorSymbolicTraits(UIFontDescriptorSymbolicTraits currentTraits, NSRange enumeratedRange)
145 | {
146 | UIFontDescriptorSymbolicTraits flag = UIFontDescriptorTraitBold;
147 | return isBold ? currentTraits | flag : currentTraits & ~flag;
148 | }];
149 | }
150 |
151 | - (void)setFontItalics:(BOOL)isItalics
152 | {
153 | [self setFontItalics:isItalics range:NSMakeRange(0, self.length)];
154 | }
155 |
156 | // TODO: Check out the effect of the NSObliquenessAttributeName attribute
157 | // to see if we can also fake italics fonts by increasing the font skew
158 | - (void)setFontItalics:(BOOL)isItalics range:(NSRange)range
159 | {
160 | [self changeFontTraitsInRange:range withBlock:^UIFontDescriptorSymbolicTraits(UIFontDescriptorSymbolicTraits currentTraits, NSRange enumeratedRange)
161 | {
162 | UIFontDescriptorSymbolicTraits flag = UIFontDescriptorTraitItalic;
163 | return isItalics ? currentTraits | flag : currentTraits & ~flag;
164 | }];
165 | }
166 |
167 | /******************************************************************************/
168 | #pragma mark - Link
169 |
170 | // TODO: Check if setting an URL also changes the text color and underline
171 | // attributes. I don't believe it does, but either way, document it.
172 | - (void)setURL:(NSURL*)linkURL range:(NSRange)range
173 | {
174 | [self removeAttribute:NSLinkAttributeName range:range]; // Work around for Apple leak
175 | if (linkURL)
176 | {
177 | [self addAttribute:NSLinkAttributeName value:(id)linkURL range:range];
178 | }
179 | }
180 |
181 | /******************************************************************************/
182 | #pragma mark - Character Spacing
183 |
184 | - (void)setCharacterSpacing:(CGFloat)chracterSpacing
185 | {
186 | [self setCharacterSpacing:chracterSpacing range:NSMakeRange(0,self.length)];
187 | }
188 | - (void)setCharacterSpacing:(CGFloat)characterSpacing range:(NSRange)range
189 | {
190 | [self addAttribute:NSKernAttributeName value:@(characterSpacing) range:range];
191 | }
192 |
193 | /******************************************************************************/
194 | #pragma mark - Subscript and Superscript
195 |
196 | - (void)setBaselineOffset:(CGFloat)offset
197 | {
198 | [self setBaselineOffset:offset range:NSMakeRange(0, self.length)];
199 | }
200 |
201 | - (void)setBaselineOffset:(CGFloat)offset range:(NSRange)range
202 | {
203 | [self removeAttribute:NSBaselineOffsetAttributeName range:range]; // Work around for Apple leak
204 | [self addAttribute:NSBaselineOffsetAttributeName value:@(offset) range:range];
205 | }
206 |
207 | - (void)setSuperscriptForRange:(NSRange)range
208 | {
209 | UIFont* font = [self attribute:NSFontAttributeName atIndex:range.location effectiveRange:NULL];
210 | CGFloat offset = + font.pointSize / 2;
211 | [self setBaselineOffset:offset range:range];
212 | }
213 |
214 | - (void)setSubscriptForRange:(NSRange)range
215 | {
216 | UIFont* font = [self attribute:NSFontAttributeName atIndex:range.location effectiveRange:NULL];
217 | CGFloat offset = - font.pointSize / 2;
218 | [self setBaselineOffset:offset range:range];
219 | }
220 |
221 | /******************************************************************************/
222 | #pragma mark - Paragraph Style
223 |
224 | - (void)setTextAlignment:(NSTextAlignment)alignment
225 | {
226 | [self setTextAlignment:alignment range:NSMakeRange(0,self.length)];
227 | }
228 |
229 | - (void)setTextAlignment:(NSTextAlignment)alignment range:(NSRange)range
230 | {
231 | [self changeParagraphStylesInRange:range withBlock:^(NSMutableParagraphStyle *paragraphStyle, NSRange enumeratedRange) {
232 | paragraphStyle.alignment = alignment;
233 | }];
234 | }
235 |
236 | - (void)setLineBreakMode:(NSLineBreakMode)lineBreakMode
237 | {
238 | [self setLineBreakMode:lineBreakMode range:NSMakeRange(0,self.length)];
239 | }
240 |
241 | - (void)setLineBreakMode:(NSLineBreakMode)lineBreakMode range:(NSRange)range
242 | {
243 | [self changeParagraphStylesInRange:range withBlock:^(NSMutableParagraphStyle *paragraphStyle, NSRange enumeratedRange) {
244 | paragraphStyle.lineBreakMode = lineBreakMode;
245 | }];
246 | }
247 |
248 |
249 | - (void)changeParagraphStylesWithBlock:(void(^)(NSMutableParagraphStyle*, NSRange))block
250 | {
251 | [self changeParagraphStylesInRange:NSMakeRange(0,self.length) withBlock:block];
252 | }
253 |
254 | - (void)changeParagraphStylesInRange:(NSRange)range withBlock:(void(^)(NSMutableParagraphStyle*, NSRange))block
255 | {
256 | NSParameterAssert(block != nil);
257 | [self beginEditing];
258 | [self enumerateParagraphStylesInRange:range
259 | includeUndefined:YES
260 | usingBlock:^(id style, NSRange aRange, BOOL *stop)
261 | {
262 | if (!style) style = [NSParagraphStyle defaultParagraphStyle];
263 | NSMutableParagraphStyle* newStyle = [style mutableCopy];
264 | block(newStyle, aRange);
265 | [self setParagraphStyle:newStyle range:aRange];
266 | }];
267 | [self endEditing];
268 | }
269 |
270 | - (void)setParagraphStyle:(NSParagraphStyle *)style
271 | {
272 | [self setParagraphStyle:style range:NSMakeRange(0,self.length)];
273 | }
274 |
275 | // TODO: Check the behavior when applying a paragraph style only to some
276 | // characters in the middle of an actual paragraph.
277 | - (void)setParagraphStyle:(NSParagraphStyle*)style range:(NSRange)range
278 | {
279 | [self removeAttribute:NSParagraphStyleAttributeName range:range]; // Work around for Apple leak
280 | [self addAttribute:NSParagraphStyleAttributeName value:(id)style range:range];
281 | }
282 |
283 | @end
284 |
--------------------------------------------------------------------------------
/Source/OHAttributedStringAdditions.h:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * This software is under the MIT License quoted below:
3 | *******************************************************************************
4 | *
5 | * Copyright (c) 2010 Olivier Halligon
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in
15 | * all copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | * THE SOFTWARE.
24 | *
25 | ******************************************************************************/
26 |
27 | #import "NSAttributedString+OHAdditions.h"
28 | #import "NSMutableAttributedString+OHAdditions.h"
29 | #import "UIFont+OHAdditions.h"
30 |
31 | #if __has_include("UILabel+OHAdditions.h")
32 | #import "UILabel+OHAdditions.h"
33 | #endif
34 |
--------------------------------------------------------------------------------
/Source/UIFont+OHAdditions.h:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | *
3 | * Copyright (c) 2010 Olivier Halligon
4 | *
5 | * Permission is hereby granted, free of charge, to any person obtaining a copy
6 | * of this software and associated documentation files (the "Software"), to deal
7 | * in the Software without restriction, including without limitation the rights
8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | * copies of the Software, and to permit persons to whom the Software is
10 | * furnished to do so, subject to the following conditions:
11 | *
12 | * The above copyright notice and this permission notice shall be included in
13 | * all copies or substantial portions of the Software.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | * THE SOFTWARE.
22 | *
23 | ******************************************************************************/
24 |
25 |
26 | #import
27 |
28 | /**
29 | * Convenience methods to create new `UIFont` instances and query font traits
30 | */
31 | @interface UIFont (OHAdditions)
32 |
33 | /**
34 | * Returns a font given a family name, size, and whether it should be bold
35 | * and/or italic.
36 | *
37 | * If the font family is not found, this will return the "Helvetica" font with
38 | * the requested size, but neither bold nor italics (This behavior is
39 | * inherited by NSFontDescriptor's own native behavior)
40 | *
41 | * @param fontFamily The name of the font family, like "Helvetica"
42 | * @param size The size of the font to return
43 | * @param isBold YES if you need the bold variant of the font
44 | * @param isItalic YES if you need the italic variant of the font
45 | *
46 | * @return The corresponding UIFont.
47 | *
48 | * @note This is a convenience method that calls +fontWithFamily:size:traits:
49 | * with the traits corresponding to the bold and/or italic flags.
50 | */
51 | + (instancetype)fontWithFamily:(NSString*)fontFamily
52 | size:(CGFloat)size
53 | bold:(BOOL)isBold
54 | italic:(BOOL)isItalic;
55 |
56 | /**
57 | * Returns a font given a family name, size and symbolic traits.
58 | *
59 | * @param fontFamily The name of the font family, like "Helvetica"
60 | * @param size The size of the font to return
61 | * @param symTraits A mask of symbolic traits, combined as an bitwise-OR mask.
62 | * e.g. UIFontDescriptorTraitBold|UIFontDescriptorTraitCondensed
63 | *
64 | * @return The corresponding UIFont.
65 | */
66 | + (instancetype)fontWithFamily:(NSString*)fontFamily
67 | size:(CGFloat)size
68 | traits:(UIFontDescriptorSymbolicTraits)symTraits;
69 |
70 | /**
71 | * Returns a font given its Postscript Name and size
72 | *
73 | * @note Font PostScript names are unlikely to change across OS versions
74 | * (whereas it seems like common, display names may change)
75 | *
76 | * @param postscriptName The PostScript name of the font
77 | * @param size The size of the font
78 | *
79 | * @return The UIFont object with the specified PS name and size.
80 | */
81 | + (instancetype)fontWithPostscriptName:(NSString*)postscriptName
82 | size:(CGFloat)size;
83 |
84 | /**
85 | * Returns a font with the same family name, size and attributs as the
86 | * receiver, but with the new symbolic traits replacing the current ones
87 | *
88 | * @param symTraits The new symbolic traits to use for the derived font
89 | *
90 | * @return The UIFont variant corresponding to the receiver but with the
91 | * new symbolic traits
92 | */
93 | - (instancetype)fontWithSymbolicTraits:(UIFontDescriptorSymbolicTraits)symTraits;
94 |
95 | /**
96 | * Returns the symbolic traits of the font, telling if its bold, italics, etc.
97 | *
98 | * @return The font symbolic traits, as returned by its font descriptor.
99 | *
100 | * @note This is a convenience method that simply calls
101 | * fontDescriptor.symbolicTraits on the receiver.
102 | */
103 | - (UIFontDescriptorSymbolicTraits)symbolicTraits;
104 |
105 | @end
106 |
--------------------------------------------------------------------------------
/Source/UIFont+OHAdditions.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIFont+OHAdditions.m
3 | // AttributedStringDemo
4 | //
5 | // Created by Olivier Halligon on 16/08/2014.
6 | // Copyright (c) 2014 AliSoftware. All rights reserved.
7 | //
8 |
9 | #import "UIFont+OHAdditions.h"
10 |
11 | @implementation UIFont (OHAdditions)
12 |
13 | + (instancetype)fontWithFamily:(NSString*)fontFamily
14 | size:(CGFloat)size
15 | bold:(BOOL)isBold
16 | italic:(BOOL)isItalic
17 | {
18 | UIFontDescriptorSymbolicTraits traits = 0;
19 | if (isBold) traits |= UIFontDescriptorTraitBold;
20 | if (isItalic) traits |= UIFontDescriptorTraitItalic;
21 |
22 | return [self fontWithFamily:fontFamily size:size traits:traits];
23 | }
24 |
25 | + (instancetype)fontWithFamily:(NSString*)fontFamily
26 | size:(CGFloat)size
27 | traits:(UIFontDescriptorSymbolicTraits)symTraits
28 | {
29 | NSDictionary* attributes = @{ UIFontDescriptorFamilyAttribute: fontFamily,
30 | UIFontDescriptorTraitsAttribute: @{UIFontSymbolicTrait:@(symTraits)}};
31 |
32 | UIFontDescriptor* desc = [UIFontDescriptor fontDescriptorWithFontAttributes:attributes];
33 | return [UIFont fontWithDescriptor:desc size:size];
34 | }
35 |
36 | + (instancetype)fontWithPostscriptName:(NSString*)postscriptName size:(CGFloat)size
37 | {
38 | // UIFontDescriptorNameAttribute = Postscript name, should not change across iOS versions.
39 | NSDictionary* attributes = @{ UIFontDescriptorNameAttribute: postscriptName };
40 |
41 | UIFontDescriptor* desc = [UIFontDescriptor fontDescriptorWithFontAttributes:attributes];
42 | return [UIFont fontWithDescriptor:desc size:size];
43 | }
44 |
45 | - (instancetype)fontWithSymbolicTraits:(UIFontDescriptorSymbolicTraits)symTraits
46 | {
47 | NSDictionary* attributes = @{UIFontDescriptorFamilyAttribute: self.familyName,
48 | UIFontDescriptorTraitsAttribute: @{UIFontSymbolicTrait:@(symTraits)}};
49 | UIFontDescriptor* desc = [UIFontDescriptor fontDescriptorWithFontAttributes:attributes];
50 | return [UIFont fontWithDescriptor:desc size:self.pointSize];
51 | }
52 |
53 | - (UIFontDescriptorSymbolicTraits)symbolicTraits
54 | {
55 | return self.fontDescriptor.symbolicTraits;
56 | }
57 |
58 | @end
59 |
--------------------------------------------------------------------------------
/Source/UILabel+OHAdditions.h:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | *
3 | * Copyright (c) 2010 Olivier Halligon
4 | *
5 | * Permission is hereby granted, free of charge, to any person obtaining a copy
6 | * of this software and associated documentation files (the "Software"), to deal
7 | * in the Software without restriction, including without limitation the rights
8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | * copies of the Software, and to permit persons to whom the Software is
10 | * furnished to do so, subject to the following conditions:
11 | *
12 | * The above copyright notice and this permission notice shall be included in
13 | * all copies or substantial portions of the Software.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | * THE SOFTWARE.
22 | *
23 | ******************************************************************************/
24 |
25 | #import
26 |
27 | /**
28 | * Convenience methods to get text layout information from the UILabel and
29 | * especially determine which character is at a given point.
30 | */
31 | @interface UILabel (OHAdditions)
32 |
33 | /**
34 | * Returns a new `NSTextContainer` configured with the current label's settings
35 | * (namely `maximumNumberOfLines` and `lineBreakMode`)
36 | */
37 | @property(nonatomic, readonly) NSTextContainer* currentTextContainer;
38 |
39 | /**
40 | * The index of the character at a given point.
41 | *
42 | * Typically used to know which character was tapped on the UILabel.
43 | *
44 | * @param point The point's coordinates, expressed in the label's coordinate
45 | * system
46 | *
47 | * @return The index of the character present at that position, or
48 | * `NSNotFound` if no character is present at that point.
49 | *
50 | * @note This method is does not handle UILabel's text shrinking feature
51 | * (like when you set `adjustFontSizeToFitWidth` to `YES`).
52 | *
53 | * @note The actual `NSTextContainer` and `NSLayoutManager` used by `UILabel`
54 | * internally to layout its text are not publicly exposed. This forces
55 | * us to create and use our own `NSLayoutManager` for the computation,
56 | * which may not be configured *exactly* the same as the private one,
57 | * so slight deviations might happen (especially when text schrinking
58 | * is on or similar stuff).
59 | *
60 | * If you really need precise detection, consider using `UITextView`
61 | * (with `editable=NO`) instead, which already support all that stuff.
62 | */
63 | - (NSUInteger)characterIndexAtPoint:(CGPoint)point;
64 |
65 | @end
66 |
--------------------------------------------------------------------------------
/Source/UILabel+OHAdditions.m:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | *
3 | * Copyright (c) 2010 Olivier Halligon
4 | *
5 | * Permission is hereby granted, free of charge, to any person obtaining a copy
6 | * of this software and associated documentation files (the "Software"), to deal
7 | * in the Software without restriction, including without limitation the rights
8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | * copies of the Software, and to permit persons to whom the Software is
10 | * furnished to do so, subject to the following conditions:
11 | *
12 | * The above copyright notice and this permission notice shall be included in
13 | * all copies or substantial portions of the Software.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | * THE SOFTWARE.
22 | *
23 | ******************************************************************************/
24 |
25 | #import "UILabel+OHAdditions.h"
26 |
27 | @implementation UILabel (OHAdditions)
28 |
29 | - (NSTextContainer*)currentTextContainer
30 | {
31 | NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:self.bounds.size];
32 | textContainer.lineFragmentPadding = 0;
33 | textContainer.maximumNumberOfLines = (NSUInteger)self.numberOfLines;
34 | textContainer.lineBreakMode = self.lineBreakMode;
35 | return textContainer;
36 | }
37 |
38 | - (NSUInteger)characterIndexAtPoint:(CGPoint)point
39 | {
40 | NSTextContainer* textContainer = self.currentTextContainer;
41 | NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:self.attributedText];
42 |
43 | NSLayoutManager *layoutManager = [NSLayoutManager new];
44 | [textStorage addLayoutManager:layoutManager];
45 | [layoutManager addTextContainer:textContainer];
46 |
47 | // UILabel centers its text vertically, so adjust the point coordinates accordingly
48 | NSRange glyphRange = [layoutManager glyphRangeForTextContainer:textContainer];
49 | CGRect wholeTextRect = [layoutManager boundingRectForGlyphRange:glyphRange
50 | inTextContainer:textContainer];
51 | point.y -= (CGRectGetHeight(self.bounds)-CGRectGetHeight(wholeTextRect))/2;
52 |
53 | // Bail early if point outside the whole text bounding rect
54 | if (!CGRectContainsPoint(wholeTextRect, point)) return NSNotFound;
55 |
56 | // ask the layoutManager which glyph is under this tapped point
57 | NSUInteger glyphIdx = [layoutManager glyphIndexForPoint:point
58 | inTextContainer:textContainer
59 | fractionOfDistanceThroughGlyph:NULL];
60 |
61 | // as explained in Apple's documentation the previous method returns the nearest glyph
62 | // if no glyph was present at that point. So if we want to ensure the point actually
63 | // lies on that glyph, we should check that explicitly
64 | CGRect glyphRect = [layoutManager boundingRectForGlyphRange:NSMakeRange(glyphIdx, 1)
65 | inTextContainer:textContainer];
66 | if (CGRectContainsPoint(glyphRect, point))
67 | {
68 | return [layoutManager characterIndexForGlyphAtIndex:glyphIdx];
69 | } else {
70 | return NSNotFound;
71 | }
72 | }
73 |
74 | @end
75 |
--------------------------------------------------------------------------------