├── .gitignore ├── Documents ├── Images │ ├── Attachment.png │ ├── Basic.png │ ├── Image.png │ └── Link.png └── README.md ├── LICENSE ├── M80AttributedLabel.podspec ├── M80AttributedLabel ├── M80AttributedLabel.h ├── M80AttributedLabel.m ├── M80AttributedLabelAttachment.h ├── M80AttributedLabelAttachment.m ├── M80AttributedLabelDefines.h ├── M80AttributedLabelURL.h ├── M80AttributedLabelURL.m ├── M80AttributedLabelURLDetector.h ├── M80AttributedLabelURLDetector.m ├── NSMutableAttributedString+M80.h └── NSMutableAttributedString+M80.m ├── OCDemo ├── Classes │ ├── AttachmentViewController.h │ ├── AttachmentViewController.m │ ├── AutoLayoutTableViewCell.h │ ├── AutoLayoutTableViewCell.m │ ├── AutoLayoutTableViewCell.xib │ ├── BaseLabelViewController.h │ ├── BaseLabelViewController.m │ ├── BasicAttributedLabelViewController.h │ ├── BasicAttributedLabelViewController.m │ ├── CustomTextViewController.h │ ├── CustomTextViewController.m │ ├── DemoTableViewController.h │ ├── DemoTableViewController.m │ ├── DemoTableViewController.xib │ ├── ImagesViewController.h │ ├── ImagesViewController.m │ ├── LineBreakModeViewController.h │ ├── LineBreakModeViewController.m │ ├── LinksViewController.h │ ├── LinksViewController.m │ ├── LongTextViewController.h │ ├── LongTextViewController.m │ ├── TextAlignmentViewController.h │ ├── TextAlignmentViewController.m │ ├── TextTableViewController.h │ └── TextTableViewController.m ├── OCDemo.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── OCDemo.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── OCDemo │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── Info.plist │ ├── OCDemo.pch │ └── main.m ├── Podfile ├── Podfile.lock └── Pods │ ├── Headers │ ├── Private │ │ └── M80AttributedLabel │ │ │ ├── M80AttributedLabel.h │ │ │ ├── M80AttributedLabelAttachment.h │ │ │ ├── M80AttributedLabelDefines.h │ │ │ ├── M80AttributedLabelURL.h │ │ │ ├── M80AttributedLabelURLDetector.h │ │ │ └── NSMutableAttributedString+M80.h │ └── Public │ │ └── M80AttributedLabel │ │ ├── M80AttributedLabel.h │ │ ├── M80AttributedLabelAttachment.h │ │ ├── M80AttributedLabelDefines.h │ │ ├── M80AttributedLabelURL.h │ │ ├── M80AttributedLabelURLDetector.h │ │ └── NSMutableAttributedString+M80.h │ ├── Local Podspecs │ └── M80AttributedLabel.podspec.json │ ├── Manifest.lock │ ├── Pods.xcodeproj │ └── project.pbxproj │ └── Target Support Files │ ├── M80AttributedLabel │ ├── M80AttributedLabel-dummy.m │ ├── M80AttributedLabel-prefix.pch │ └── M80AttributedLabel.xcconfig │ └── Pods-OCDemo │ ├── Pods-OCDemo-acknowledgements.markdown │ ├── Pods-OCDemo-acknowledgements.plist │ ├── Pods-OCDemo-dummy.m │ ├── Pods-OCDemo-frameworks.sh │ ├── Pods-OCDemo-resources.sh │ ├── Pods-OCDemo.debug.xcconfig │ └── Pods-OCDemo.release.xcconfig ├── README.md ├── Resource ├── avatar.png ├── haha.png ├── play@2x.png └── test.txt ├── SwiftDemo ├── Classes │ ├── AttachmentViewController.swift │ ├── BaseViewController.swift │ ├── BasicAttributedLabelViewController.swift │ ├── CustomTextViewController.swift │ ├── DemoTableViewController.swift │ ├── ImagesViewController.swift │ ├── LineBreakModeViewController.swift │ ├── LinksViewController.swift │ ├── LongTextViewController.swift │ ├── SwiftDemo-Bridging-Header.h │ ├── TextAlignmentViewController.swift │ └── Util │ │ └── Util.swift ├── Podfile ├── Podfile.lock ├── Pods │ ├── Headers │ │ ├── Private │ │ │ └── M80AttributedLabel │ │ │ │ ├── M80AttributedLabel.h │ │ │ │ ├── M80AttributedLabelAttachment.h │ │ │ │ ├── M80AttributedLabelDefines.h │ │ │ │ ├── M80AttributedLabelURL.h │ │ │ │ ├── M80AttributedLabelURLDetector.h │ │ │ │ └── NSMutableAttributedString+M80.h │ │ └── Public │ │ │ └── M80AttributedLabel │ │ │ ├── M80AttributedLabel.h │ │ │ ├── M80AttributedLabelAttachment.h │ │ │ ├── M80AttributedLabelDefines.h │ │ │ ├── M80AttributedLabelURL.h │ │ │ ├── M80AttributedLabelURLDetector.h │ │ │ └── NSMutableAttributedString+M80.h │ ├── Local Podspecs │ │ └── M80AttributedLabel.podspec.json │ ├── Manifest.lock │ ├── Pods.xcodeproj │ │ └── project.pbxproj │ └── Target Support Files │ │ ├── M80AttributedLabel │ │ ├── M80AttributedLabel-dummy.m │ │ ├── M80AttributedLabel-prefix.pch │ │ └── M80AttributedLabel.xcconfig │ │ └── Pods-SwiftDemo │ │ ├── Pods-SwiftDemo-acknowledgements.markdown │ │ ├── Pods-SwiftDemo-acknowledgements.plist │ │ ├── Pods-SwiftDemo-dummy.m │ │ ├── Pods-SwiftDemo-frameworks.sh │ │ ├── Pods-SwiftDemo-resources.sh │ │ ├── Pods-SwiftDemo.debug.xcconfig │ │ └── Pods-SwiftDemo.release.xcconfig ├── SwiftDemo.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── SwiftDemo.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── SwiftDemo │ ├── AppDelegate.swift │ ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Info.plist │ └── ViewController.swift └── pod_push.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | -------------------------------------------------------------------------------- /Documents/Images/Attachment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangwangfeng/M80AttributedLabel/9b3431f1094f48b77e505697fb31e714fa99b830/Documents/Images/Attachment.png -------------------------------------------------------------------------------- /Documents/Images/Basic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangwangfeng/M80AttributedLabel/9b3431f1094f48b77e505697fb31e714fa99b830/Documents/Images/Basic.png -------------------------------------------------------------------------------- /Documents/Images/Image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangwangfeng/M80AttributedLabel/9b3431f1094f48b77e505697fb31e714fa99b830/Documents/Images/Image.png -------------------------------------------------------------------------------- /Documents/Images/Link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangwangfeng/M80AttributedLabel/9b3431f1094f48b77e505697fb31e714fa99b830/Documents/Images/Link.png -------------------------------------------------------------------------------- /Documents/README.md: -------------------------------------------------------------------------------- 1 | M80AttributedLabel 2 | ================== 3 | 4 | 5 | 富文本显示组件 [English Version](./../README.md) 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 | * iOS 7.0 及以上 31 | * 需要 ARC 32 | 33 | # 集成 34 | 35 | ### Podfile 36 | 37 | ```ruby 38 | pod 'M80AttributedLabel' 39 | ``` 40 | 41 | ### 手动集成 42 | 43 | * `git clone https://github.com/xiangwangfeng/M80AttributedLabel.git` 44 | * 拷贝 `Class/M80AttributedLabel` 中的源代码到你的工程中 45 | * 添加 `CoreText.framework` 46 | 47 | # 使用方法 48 | 49 | ## 基本使用 50 | 51 | ```objc 52 | 53 | M80AttributedLabel *label = [[M80AttributedLabel alloc]initWithFrame:CGRectZero]; 54 | 55 | label.text = @"Hello M80AttributedLabel"; 56 | label.font = [UIFont fontWithName:@"Zapfino" size:25]; 57 | label.textColor = M80RGB(0xFF9F00); 58 | label.shadowColor = [UIColor grayColor]; 59 | label.shadowOffset= CGSizeMake(1, 1); 60 | label.shadowBlur = 1; 61 | 62 | label.frame = CGRectInset(self.view.bounds,20,20); 63 | 64 | [self.view addSubview:label]; 65 | 66 | ``` 67 | 68 | 69 | 70 | ## 链接 71 | 72 | ```objc 73 | 74 | M80AttributedLabel *label = [[M80AttributedLabel alloc]initWithFrame:CGRectZero]; 75 | 76 | NSString *text = @"The game which I current play is hearthstone,and its website is www.hearthstone.com.cn"; 77 | NSRange range = [text rangeOfString:@"hearthstone"]; 78 | label.text = text; 79 | [label addCustomLink:[NSValue valueWithRange:range] 80 | forRange:range]; 81 | label.delegate = self; 82 | 83 | label.frame = CGRectInset(self.view.bounds,20,20); 84 | 85 | [self.view addSubview:label]; 86 | 87 | 88 | ``` 89 | 90 | 91 | 92 | 93 | ## 图片 94 | 95 | ```objc 96 | 97 | 98 | M80AttributedLabel *label = [[M80AttributedLabel alloc]initWithFrame:CGRectZero]; 99 | label.lineSpacing = 5.0; 100 | 101 | [label appendImage:[UIImage imageNamed:@"avatar"] 102 | maxSize:CGSizeMake(40, 40) 103 | margin:UIEdgeInsetsZero 104 | alignment:M80ImageAlignmentBottom]; 105 | 106 | NSString *text = @"say:\n有人问一位登山家为什么要去登山——谁都知道登山这件事既危险,又没什么实际的好处。[haha][haha][haha][haha]他回答道:“因为那座山峰在那里。”我喜欢这个答案,因为里面包含着幽默感——明明是自己想要登山,偏说是山在那里使他心里痒痒。除此之外,我还喜欢这位登山家干的事,没来由地往悬崖上爬。[haha][haha][haha]它会导致肌肉疼痛,还要冒摔出脑子的危险,所以一般人尽量避免爬山。[haha][haha][haha]用热力学的角度来看,这是个反熵的现象,所发趋害避利肯定反熵。"; 107 | 108 | //replace [haha] by image 109 | NSArray *components = [text componentsSeparatedByString:@"[haha]"]; 110 | NSUInteger count = [components count]; 111 | for (NSUInteger i = 0; i < count; i++) 112 | { 113 | [label appendText:[components objectAtIndex:i]]; 114 | if (i != count - 1) 115 | { 116 | [label appendImage:[UIImage imageNamed:@"haha"] 117 | maxSize:CGSizeMake(15, 15) 118 | margin:UIEdgeInsetsZero 119 | alignment:M80ImageAlignmentCenter]; 120 | } 121 | } 122 | 123 | label.frame = CGRectInset(self.view.bounds,20,20); 124 | [self.view addSubview:label]; 125 | 126 | 127 | ``` 128 | 129 | 130 | 131 | ## 附件 132 | 133 | ```objc 134 | 135 | M80AttributedLabel *label = [[M80AttributedLabel alloc]initWithFrame:CGRectZero]; 136 | 137 | for (NSInteger i = 0; i < 3; i++) 138 | { 139 | [label appendText:@"Click the icon to fire event"]; 140 | 141 | UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; 142 | button setBackgroundImage:[UIImage imageNamed:@"play"] forState:UIControlStateNormal]; 143 | [button addTarget:self 144 | action:@selector(buttonClicked:) 145 | forControlEvents:UIControlEventTouchUpInside]; 146 | [button setBounds:CGRectMake(0, 0, 30, 30)]; 147 | [button setTag:i]; 148 | [label appendView:button]; 149 | 150 | [label appendText:@"\n\n\n"]; 151 | } 152 | 153 | 154 | label.frame = CGRectInset(self.view.bounds,20,20); 155 | [self.view addSubview:label]; 156 | 157 | ``` 158 | 159 | 160 | 161 | # 联系我 162 | * https://github.com/xiangwangfeng 163 | * http://www.xiangwangfeng.com 164 | * xiangwangfeng@gmail.com 165 | * http://weibo.com/epmao 166 | 167 | [Apache]: http://www.apache.org/licenses/LICENSE-2.0 168 | [MIT]: http://www.opensource.org/licenses/mit-license.php 169 | [GPL]: http://www.gnu.org/licenses/gpl.html 170 | [BSD]: http://opensource.org/licenses/bsd-license.php 171 | 172 | # 许可证 173 | 174 | M80AttributedLabel 使用 [MIT license][MIT] 许可证,详情见 LICENSE 文件。 175 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Xiang Wangfeng (http://xiangwangfeng.com) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /M80AttributedLabel.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'M80AttributedLabel' 3 | s.version = '1.9.9' 4 | s.authors = {'Xiang Wangfeng' => 'xiangwangfeng@gmail.com'} 5 | s.homepage = 'https://github.com/xiangwangfeng/M80AttributedLabel/' 6 | s.summary = 'Another attributed label using CoreText' 7 | s.source = {:git => 'https://github.com/xiangwangfeng/M80AttributedLabel.git', :tag => s.version.to_s} 8 | s.license = 'MIT' 9 | 10 | s.requires_arc = true 11 | 12 | s.platform = :ios 13 | s.ios.deployment_target = '7.0' 14 | 15 | s.frameworks = 'CoreText', 'CoreGraphics', 'QuartzCore' 16 | s.source_files = 'M80AttributedLabel/*.{h,m}' 17 | end 18 | -------------------------------------------------------------------------------- /M80AttributedLabel/M80AttributedLabel.h: -------------------------------------------------------------------------------- 1 | // 2 | // M80AttributedLabel.h 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 13-9-1. 6 | // Copyright (c) 2013年 www.xiangwangfeng.com. All rights reserved. 7 | // 8 | 9 | #import "M80AttributedLabelDefines.h" 10 | #import "M80AttributedLabelAttachment.h" 11 | #import "M80AttributedLabelURL.h" 12 | #import "M80AttributedLabelURLDetector.h" 13 | #import "NSMutableAttributedString+M80.h" 14 | 15 | NS_ASSUME_NONNULL_BEGIN 16 | 17 | @class M80AttributedLabelURL; 18 | 19 | @interface M80AttributedLabel : UIView 20 | @property (nonatomic,weak,nullable) id delegate; 21 | @property (nonatomic,strong,nullable) UIFont *font; //字体 22 | @property (nonatomic,strong,nullable) UIColor *textColor; //文字颜色 23 | @property (nonatomic,strong,nullable) UIColor *highlightColor; //链接点击时背景高亮色 24 | @property (nonatomic,strong,nullable) UIColor *linkColor; //链接色 25 | @property (nonatomic,strong,nullable) UIColor *shadowColor; //阴影颜色 26 | @property (nonatomic,assign) CGSize shadowOffset; //阴影offset 27 | @property (nonatomic,assign) CGFloat shadowBlur; //阴影半径 28 | @property (nonatomic,assign) BOOL underLineForLink; //链接是否带下划线 29 | @property (nonatomic,assign) BOOL autoDetectLinks; //自动检测 30 | @property (nonatomic,assign) NSInteger numberOfLines; //行数 31 | @property (nonatomic,assign) CTTextAlignment textAlignment; //文字排版样式 32 | @property (nonatomic,assign) CTLineBreakMode lineBreakMode; //LineBreakMode 33 | @property (nonatomic,assign) CGFloat lineSpacing; //行间距 34 | @property (nonatomic,assign) CGFloat paragraphSpacing; //段间距 35 | @property (nonatomic,copy,nullable) NSString *text; //普通文本 36 | @property (nonatomic,copy,nullable) NSAttributedString *attributedText; //属性文本 37 | 38 | 39 | //添加文本 40 | - (void)appendText:(NSString *)text; 41 | - (void)appendAttributedText:(NSAttributedString *)attributedText; 42 | 43 | //图片 44 | - (void)appendImage:(UIImage *)image; 45 | - (void)appendImage:(UIImage *)image 46 | maxSize:(CGSize)maxSize; 47 | - (void)appendImage:(UIImage *)image 48 | maxSize:(CGSize)maxSize 49 | margin:(UIEdgeInsets)margin; 50 | - (void)appendImage:(UIImage *)image 51 | maxSize:(CGSize)maxSize 52 | margin:(UIEdgeInsets)margin 53 | alignment:(M80ImageAlignment)alignment; 54 | 55 | //UI控件 56 | - (void)appendView:(UIView *)view; 57 | - (void)appendView:(UIView *)view 58 | margin:(UIEdgeInsets)margin; 59 | - (void)appendView:(UIView *)view 60 | margin:(UIEdgeInsets)margin 61 | alignment:(M80ImageAlignment)alignment; 62 | 63 | 64 | //添加自定义链接 65 | - (void)addCustomLink:(id)linkData 66 | forRange:(NSRange)range; 67 | 68 | - (void)addCustomLink:(id)linkData 69 | forRange:(NSRange)range 70 | linkColor:(UIColor *)color; 71 | 72 | 73 | //大小 74 | - (CGSize)sizeThatFits:(CGSize)size; 75 | 76 | @end 77 | 78 | NS_ASSUME_NONNULL_END 79 | -------------------------------------------------------------------------------- /M80AttributedLabel/M80AttributedLabelAttachment.h: -------------------------------------------------------------------------------- 1 | // 2 | // M80AttributedLabelAttachment.h 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 13-8-31. 6 | // Copyright (c) 2013年 www.xiangwangfeng.com. All rights reserved. 7 | // 8 | 9 | #import "M80AttributedLabelDefines.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | void deallocCallback(void* ref); 14 | CGFloat ascentCallback(void *ref); 15 | CGFloat descentCallback(void *ref); 16 | CGFloat widthCallback(void* ref); 17 | 18 | @interface M80AttributedLabelAttachment : NSObject 19 | @property (nonatomic,strong) id content; 20 | @property (nonatomic,assign) UIEdgeInsets margin; 21 | @property (nonatomic,assign) M80ImageAlignment alignment; 22 | @property (nonatomic,assign) CGFloat fontAscent; 23 | @property (nonatomic,assign) CGFloat fontDescent; 24 | @property (nonatomic,assign) CGSize maxSize; 25 | 26 | 27 | + (M80AttributedLabelAttachment *)attachmentWith:(id)content 28 | margin:(UIEdgeInsets)margin 29 | alignment:(M80ImageAlignment)alignment 30 | maxSize:(CGSize)maxSize; 31 | 32 | - (CGSize)boxSize; 33 | 34 | @end 35 | 36 | 37 | NS_ASSUME_NONNULL_END 38 | -------------------------------------------------------------------------------- /M80AttributedLabel/M80AttributedLabelAttachment.m: -------------------------------------------------------------------------------- 1 | // 2 | // M80AttributedLabelAttachment.m 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 13-8-31. 6 | // Copyright (c) 2013年 www.xiangwangfeng.com. All rights reserved. 7 | // 8 | 9 | #import "M80AttributedLabelAttachment.h" 10 | 11 | void deallocCallback(void* ref) 12 | { 13 | 14 | } 15 | 16 | CGFloat ascentCallback(void *ref) 17 | { 18 | M80AttributedLabelAttachment *image = (__bridge M80AttributedLabelAttachment *)ref; 19 | CGFloat ascent = 0; 20 | CGFloat height = [image boxSize].height; 21 | switch (image.alignment) 22 | { 23 | case M80ImageAlignmentTop: 24 | ascent = image.fontAscent; 25 | break; 26 | case M80ImageAlignmentCenter: 27 | { 28 | CGFloat fontAscent = image.fontAscent; 29 | CGFloat fontDescent = image.fontDescent; 30 | CGFloat baseLine = (fontAscent + fontDescent) / 2 - fontDescent; 31 | ascent = height / 2 + baseLine; 32 | } 33 | break; 34 | case M80ImageAlignmentBottom: 35 | ascent = height - image.fontDescent; 36 | break; 37 | default: 38 | break; 39 | } 40 | return ascent; 41 | } 42 | 43 | CGFloat descentCallback(void *ref) 44 | { 45 | M80AttributedLabelAttachment *image = (__bridge M80AttributedLabelAttachment *)ref; 46 | CGFloat descent = 0; 47 | CGFloat height = [image boxSize].height; 48 | switch (image.alignment) 49 | { 50 | case M80ImageAlignmentTop: 51 | { 52 | descent = height - image.fontAscent; 53 | break; 54 | } 55 | case M80ImageAlignmentCenter: 56 | { 57 | CGFloat fontAscent = image.fontAscent; 58 | CGFloat fontDescent = image.fontDescent; 59 | CGFloat baseLine = (fontAscent + fontDescent) / 2 - fontDescent; 60 | descent = height / 2 - baseLine; 61 | } 62 | break; 63 | case M80ImageAlignmentBottom: 64 | { 65 | descent = image.fontDescent; 66 | break; 67 | } 68 | default: 69 | break; 70 | } 71 | 72 | return descent; 73 | 74 | } 75 | 76 | CGFloat widthCallback(void* ref) 77 | { 78 | M80AttributedLabelAttachment *image = (__bridge M80AttributedLabelAttachment *)ref; 79 | return [image boxSize].width; 80 | } 81 | 82 | #pragma mark - M80AttributedLabelImage 83 | @interface M80AttributedLabelAttachment () 84 | - (CGSize)calculateContentSize; 85 | - (CGSize)attachmentSize; 86 | @end 87 | 88 | @implementation M80AttributedLabelAttachment 89 | 90 | 91 | 92 | 93 | + (M80AttributedLabelAttachment *)attachmentWith:(id)content 94 | margin:(UIEdgeInsets)margin 95 | alignment:(M80ImageAlignment)alignment 96 | maxSize:(CGSize)maxSize 97 | { 98 | M80AttributedLabelAttachment *attachment = [[M80AttributedLabelAttachment alloc]init]; 99 | attachment.content = content; 100 | attachment.margin = margin; 101 | attachment.alignment = alignment; 102 | attachment.maxSize = maxSize; 103 | return attachment; 104 | } 105 | 106 | 107 | - (CGSize)boxSize 108 | { 109 | CGSize contentSize = [self attachmentSize]; 110 | if (_maxSize.width > 0 &&_maxSize.height > 0 && 111 | contentSize.width > 0 && contentSize.height > 0) 112 | { 113 | contentSize = [self calculateContentSize]; 114 | } 115 | return CGSizeMake(contentSize.width + _margin.left + _margin.right, 116 | contentSize.height+ _margin.top + _margin.bottom); 117 | } 118 | 119 | 120 | #pragma mark - 辅助方法 121 | - (CGSize)calculateContentSize 122 | { 123 | CGSize attachmentSize = [self attachmentSize]; 124 | CGFloat width = attachmentSize.width; 125 | CGFloat height = attachmentSize.height; 126 | CGFloat newWidth = _maxSize.width; 127 | CGFloat newHeight = _maxSize.height; 128 | if (width <= newWidth && 129 | height<= newHeight) 130 | { 131 | return attachmentSize; 132 | } 133 | CGSize size; 134 | if (width / height > newWidth / newHeight) 135 | { 136 | size = CGSizeMake(newWidth, newWidth * height / width); 137 | } 138 | else 139 | { 140 | size = CGSizeMake(newHeight * width / height, newHeight); 141 | } 142 | return size; 143 | } 144 | 145 | - (CGSize)attachmentSize 146 | { 147 | CGSize size = CGSizeZero; 148 | if ([_content isKindOfClass:[UIImage class]]) 149 | { 150 | size = [((UIImage *)_content) size]; 151 | } 152 | else if ([_content isKindOfClass:[UIView class]]) 153 | { 154 | size = [((UIView *)_content) bounds].size; 155 | } 156 | return size; 157 | } 158 | @end 159 | -------------------------------------------------------------------------------- /M80AttributedLabel/M80AttributedLabelDefines.h: -------------------------------------------------------------------------------- 1 | // 2 | // M80AttributedLabelDefines.h 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 13-8-31. 6 | // Copyright (c) 2013年 www.xiangwangfeng.com. All rights reserved. 7 | // 8 | 9 | #ifndef M80AttributedLabel_M80AttributedLabelDefines_h 10 | #define M80AttributedLabel_M80AttributedLabelDefines_h 11 | 12 | #import 13 | #import 14 | #import 15 | 16 | NS_ASSUME_NONNULL_BEGIN 17 | 18 | typedef NS_OPTIONS(NSUInteger, M80ImageAlignment) { 19 | M80ImageAlignmentTop, 20 | M80ImageAlignmentCenter, 21 | M80ImageAlignmentBottom 22 | }; 23 | 24 | @class M80AttributedLabel; 25 | 26 | @protocol M80AttributedLabelDelegate 27 | - (void)m80AttributedLabel:(M80AttributedLabel *)label 28 | clickedOnLink:(id)linkData; 29 | 30 | @end 31 | 32 | NS_ASSUME_NONNULL_END 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /M80AttributedLabel/M80AttributedLabelURL.h: -------------------------------------------------------------------------------- 1 | // 2 | // M80AttributedLabelURL.h 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 13-8-31. 6 | // Copyright (c) 2013年 www.xiangwangfeng.com. All rights reserved. 7 | // 8 | 9 | #import "M80AttributedLabelDefines.h" 10 | 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @class M80AttributedLabelURL; 15 | 16 | @interface M80AttributedLabelURL : NSObject 17 | @property (nonatomic,strong) id linkData; 18 | @property (nonatomic,assign) NSRange range; 19 | @property (nonatomic,strong,nullable) UIColor *color; 20 | 21 | + (M80AttributedLabelURL *)urlWithLinkData:(id)linkData 22 | range:(NSRange)range 23 | color:(nullable UIColor *)color; 24 | 25 | 26 | 27 | @end 28 | 29 | 30 | NS_ASSUME_NONNULL_END 31 | -------------------------------------------------------------------------------- /M80AttributedLabel/M80AttributedLabelURL.m: -------------------------------------------------------------------------------- 1 | // 2 | // M80AttributedLabelURL.m 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 13-8-31. 6 | // Copyright (c) 2013年 www.xiangwangfeng.com. All rights reserved. 7 | // 8 | 9 | #import "M80AttributedLabelURL.h" 10 | 11 | 12 | @implementation M80AttributedLabelURL 13 | 14 | + (M80AttributedLabelURL *)urlWithLinkData:(id)linkData 15 | range:(NSRange)range 16 | color:(UIColor *)color 17 | { 18 | M80AttributedLabelURL *url = [[M80AttributedLabelURL alloc]init]; 19 | url.linkData = linkData; 20 | url.range = range; 21 | url.color = color; 22 | return url; 23 | 24 | } 25 | 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /M80AttributedLabel/M80AttributedLabelURLDetector.h: -------------------------------------------------------------------------------- 1 | // 2 | // M80AttributedLabelURLDetector.h 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 2019/4/2. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | @class M80AttributedLabelURL; 12 | 13 | typedef void(^M80LinkDetectCompletion)(NSArray * _Nullable links); 14 | 15 | @protocol M80AttributedLabelCustomURLDetector 16 | - (void)detectLinks:(nullable NSString *)plainText 17 | completion:(M80LinkDetectCompletion)completion; 18 | @end 19 | 20 | @interface M80AttributedLabelURLDetector : NSObject 21 | @property (nonatomic,strong) id detector; 22 | 23 | + (instancetype)shared; 24 | 25 | - (void)detectLinks:(nullable NSString *)plainText 26 | completion:(M80LinkDetectCompletion)completion; 27 | @end 28 | 29 | NS_ASSUME_NONNULL_END 30 | -------------------------------------------------------------------------------- /M80AttributedLabel/M80AttributedLabelURLDetector.m: -------------------------------------------------------------------------------- 1 | // 2 | // M80AttributedLabelURLDetector.m 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 2019/4/2. 6 | // 7 | 8 | #import "M80AttributedLabelURLDetector.h" 9 | #import "M80AttributedLabelURL.h" 10 | 11 | @implementation M80AttributedLabelURLDetector 12 | + (instancetype)shared 13 | { 14 | static M80AttributedLabelURLDetector *instance = nil; 15 | static dispatch_once_t onceToken; 16 | dispatch_once(&onceToken, ^{ 17 | instance = [M80AttributedLabelURLDetector new]; 18 | }); 19 | return instance; 20 | } 21 | 22 | - (void)detectLinks:(nullable NSString *)plainText 23 | completion:(M80LinkDetectCompletion)completion 24 | { 25 | if (completion == nil) 26 | { 27 | return; 28 | } 29 | 30 | if (self.detector) 31 | { 32 | [self.detector detectLinks:plainText 33 | completion:completion]; 34 | } 35 | else 36 | { 37 | NSMutableArray *links = nil; 38 | if ([plainText length]) 39 | { 40 | links = [NSMutableArray array]; 41 | NSDataDetector *detector = [self linkDetector]; 42 | [detector enumerateMatchesInString:plainText 43 | options:0 44 | range:NSMakeRange(0, [plainText length]) 45 | usingBlock:^(NSTextCheckingResult * _Nullable result, NSMatchingFlags flags, BOOL * _Nonnull stop) { 46 | NSRange range = result.range; 47 | NSString *text = [plainText substringWithRange:range]; 48 | M80AttributedLabelURL *link = [M80AttributedLabelURL urlWithLinkData:text 49 | range:range 50 | color:nil]; 51 | [links addObject:link]; 52 | }]; 53 | } 54 | completion(links); 55 | } 56 | } 57 | 58 | - (NSDataDetector *)linkDetector 59 | { 60 | static NSString *M80LinkDetectorKey = @"M80LinkDetectorKey"; 61 | 62 | NSMutableDictionary *dict = [[NSThread currentThread] threadDictionary]; 63 | NSDataDetector *detector = dict[M80LinkDetectorKey]; 64 | if (detector == nil) 65 | { 66 | detector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink | NSTextCheckingTypePhoneNumber 67 | error:nil]; 68 | if (detector) 69 | { 70 | dict[M80LinkDetectorKey] = detector; 71 | } 72 | } 73 | return detector; 74 | } 75 | 76 | @end 77 | -------------------------------------------------------------------------------- /M80AttributedLabel/NSMutableAttributedString+M80.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSMutableAttributedString+M80.h 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 13-8-31. 6 | // Copyright (c) 2013年 www.xiangwangfeng.com. All rights reserved. 7 | // 8 | 9 | #import "M80AttributedLabelDefines.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface NSMutableAttributedString (M80) 14 | 15 | - (void)m80_setTextColor:(UIColor*)color; 16 | - (void)m80_setTextColor:(UIColor*)color range:(NSRange)range; 17 | 18 | - (void)m80_setFont:(UIFont*)font; 19 | - (void)m80_setFont:(UIFont*)font range:(NSRange)range; 20 | 21 | - (void)m80_setUnderlineStyle:(CTUnderlineStyle)style 22 | modifier:(CTUnderlineStyleModifiers)modifier; 23 | - (void)m80_setUnderlineStyle:(CTUnderlineStyle)style 24 | modifier:(CTUnderlineStyleModifiers)modifier 25 | range:(NSRange)range; 26 | 27 | @end 28 | 29 | NS_ASSUME_NONNULL_END 30 | -------------------------------------------------------------------------------- /M80AttributedLabel/NSMutableAttributedString+M80.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSMutableAttributedString+M80.m 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 13-8-31. 6 | // Copyright (c) 2013年 www.xiangwangfeng.com. All rights reserved. 7 | // 8 | 9 | #import "NSMutableAttributedString+M80.h" 10 | 11 | @implementation NSMutableAttributedString (M80) 12 | 13 | - (void)m80_setTextColor:(UIColor*)color 14 | { 15 | [self m80_setTextColor:color range:NSMakeRange(0, [self length])]; 16 | } 17 | 18 | - (void)m80_setTextColor:(UIColor*)color range:(NSRange)range 19 | { 20 | [self removeAttribute:(NSString *)kCTForegroundColorAttributeName range:range]; 21 | if (color.CGColor) 22 | { 23 | 24 | 25 | [self addAttribute:(NSString *)kCTForegroundColorAttributeName 26 | value:(id)color.CGColor 27 | range:range]; 28 | } 29 | } 30 | 31 | 32 | - (void)m80_setFont:(UIFont*)font 33 | { 34 | [self m80_setFont:font range:NSMakeRange(0, [self length])]; 35 | } 36 | 37 | - (void)m80_setFont:(UIFont*)font range:(NSRange)range 38 | { 39 | if (font) 40 | { 41 | [self removeAttribute:(NSString*)kCTFontAttributeName range:range]; 42 | 43 | CTFontRef fontRef = CTFontCreateWithFontDescriptor((__bridge CTFontDescriptorRef)font.fontDescriptor, font.pointSize, nil); 44 | if (nil != fontRef) 45 | { 46 | [self addAttribute:(NSString *)kCTFontAttributeName value:(__bridge id)fontRef range:range]; 47 | CFRelease(fontRef); 48 | } 49 | } 50 | } 51 | 52 | - (void)m80_setUnderlineStyle:(CTUnderlineStyle)style 53 | modifier:(CTUnderlineStyleModifiers)modifier 54 | { 55 | [self m80_setUnderlineStyle:style 56 | modifier:modifier 57 | range:NSMakeRange(0, self.length)]; 58 | } 59 | 60 | - (void)m80_setUnderlineStyle:(CTUnderlineStyle)style 61 | modifier:(CTUnderlineStyleModifiers)modifier 62 | range:(NSRange)range 63 | { 64 | [self removeAttribute:(NSString *)kCTUnderlineColorAttributeName range:range]; 65 | [self addAttribute:(NSString *)kCTUnderlineStyleAttributeName 66 | value:[NSNumber numberWithInt:(style|modifier)] 67 | range:range]; 68 | 69 | } 70 | 71 | @end 72 | -------------------------------------------------------------------------------- /OCDemo/Classes/AttachmentViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // AttachmentViewController.h 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 5/21/14. 6 | // Copyright (c) 2014 www.xiangwangfeng.com. All rights reserved. 7 | // 8 | 9 | #import "BaseLabelViewController.h" 10 | 11 | @interface AttachmentViewController : BaseLabelViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /OCDemo/Classes/AttachmentViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // AttachmentViewController.m 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 5/21/14. 6 | // Copyright (c) 2014 www.xiangwangfeng.com. All rights reserved. 7 | // 8 | 9 | #import "AttachmentViewController.h" 10 | #import "M80AttributedLabel.h" 11 | 12 | @interface AttachmentViewController () 13 | @end 14 | 15 | @implementation AttachmentViewController 16 | 17 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 18 | { 19 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 20 | if (self) { 21 | // Custom initialization 22 | } 23 | return self; 24 | } 25 | 26 | - (void)viewDidLoad 27 | { 28 | [super viewDidLoad]; 29 | 30 | self.title = @"Attachment"; 31 | 32 | M80AttributedLabel *label = [[M80AttributedLabel alloc]initWithFrame:CGRectZero]; 33 | 34 | for (NSInteger i = 0; i < 3; i++) 35 | { 36 | [label appendText:@"Click the icon to fire event"]; 37 | 38 | UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; 39 | [button setBackgroundImage:[UIImage imageNamed:@"play"] forState:UIControlStateNormal]; 40 | [button addTarget:self 41 | action:@selector(buttonClicked:) 42 | forControlEvents:UIControlEventTouchUpInside]; 43 | [button setBounds:CGRectMake(0, 0, 30, 30)]; 44 | [button setTag:i]; 45 | [label appendView:button]; 46 | 47 | [label appendText:@"\n\n\n"]; 48 | } 49 | 50 | 51 | 52 | label.frame = CGRectInset(self.view.bounds,20,20); 53 | [self.view addSubview:label]; 54 | 55 | 56 | } 57 | 58 | - (void)didReceiveMemoryWarning 59 | { 60 | [super didReceiveMemoryWarning]; 61 | } 62 | 63 | - (void)buttonClicked:(id)sender 64 | { 65 | NSString *message = [NSString stringWithFormat:@"button tag is %zd",[(UIButton *)sender tag]]; 66 | 67 | UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"you click a button" 68 | message:message 69 | preferredStyle:UIAlertControllerStyleAlert]; 70 | UIAlertAction *action = [UIAlertAction actionWithTitle:@"Cancel" 71 | style:UIAlertActionStyleCancel 72 | handler:nil]; 73 | [controller addAction:action]; 74 | [self presentViewController:controller 75 | animated:YES 76 | completion:nil]; 77 | 78 | } 79 | 80 | 81 | 82 | @end 83 | -------------------------------------------------------------------------------- /OCDemo/Classes/AutoLayoutTableViewCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // AutoLayoutTableViewCell.h 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 9/17/14. 6 | // Copyright (c) 2014 www.xiangwangfeng.com. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "M80AttributedLabel.h" 11 | 12 | @interface AutoLayoutTableViewCell : UITableViewCell 13 | @property (strong, nonatomic) IBOutlet M80AttributedLabel *autoLayoutLabel; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /OCDemo/Classes/AutoLayoutTableViewCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // AutoLayoutTableViewCell.m 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 9/17/14. 6 | // Copyright (c) 2014 www.xiangwangfeng.com. All rights reserved. 7 | // 8 | 9 | #import "AutoLayoutTableViewCell.h" 10 | 11 | @implementation AutoLayoutTableViewCell 12 | 13 | - (void)awakeFromNib { 14 | [super awakeFromNib]; 15 | } 16 | 17 | - (void)setSelected:(BOOL)selected animated:(BOOL)animated { 18 | [super setSelected:selected animated:animated]; 19 | 20 | // Configure the view for the selected state 21 | } 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /OCDemo/Classes/AutoLayoutTableViewCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /OCDemo/Classes/BaseLabelViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // BaseLabelViewController.h 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 5/21/14. 6 | // Copyright (c) 2014 www.xiangwangfeng.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface BaseLabelViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /OCDemo/Classes/BaseLabelViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // BaseLabelViewController.m 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 5/21/14. 6 | // Copyright (c) 2014 www.xiangwangfeng.com. All rights reserved. 7 | // 8 | 9 | #import "BaseLabelViewController.h" 10 | 11 | @interface BaseLabelViewController () 12 | 13 | @end 14 | 15 | @implementation BaseLabelViewController 16 | 17 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 18 | { 19 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 20 | if (self) { 21 | // Custom initialization 22 | } 23 | return self; 24 | } 25 | 26 | - (void)viewDidLoad 27 | { 28 | [super viewDidLoad]; 29 | 30 | if ([self respondsToSelector:@selector(setEdgesForExtendedLayout:)]) { 31 | self.edgesForExtendedLayout = UIRectEdgeNone; 32 | } 33 | self.view.backgroundColor = [UIColor whiteColor]; 34 | } 35 | 36 | - (void)didReceiveMemoryWarning 37 | { 38 | [super didReceiveMemoryWarning]; 39 | // Dispose of any resources that can be recreated. 40 | } 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /OCDemo/Classes/BasicAttributedLabelViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // BasicAttributedLabelViewController.h 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 5/21/14. 6 | // Copyright (c) 2014 www.xiangwangfeng.com. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "BaseLabelViewController.h" 11 | 12 | @interface BasicAttributedLabelViewController : BaseLabelViewController 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /OCDemo/Classes/BasicAttributedLabelViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // BasicAttributedLabelViewController.m 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 5/21/14. 6 | // Copyright (c) 2014 www.xiangwangfeng.com. All rights reserved. 7 | // 8 | 9 | #import "BasicAttributedLabelViewController.h" 10 | #import "M80AttributedLabel.h" 11 | 12 | @interface BasicAttributedLabelViewController () 13 | 14 | @end 15 | 16 | @implementation BasicAttributedLabelViewController 17 | 18 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 19 | { 20 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 21 | if (self) { 22 | 23 | } 24 | return self; 25 | } 26 | 27 | - (void)viewDidLoad 28 | { 29 | [super viewDidLoad]; 30 | 31 | self.title = @"Basic"; 32 | 33 | M80AttributedLabel *label = [[M80AttributedLabel alloc]initWithFrame:CGRectZero]; 34 | 35 | label.text = @"Hello M80AttributedLabel"; 36 | label.font = [UIFont fontWithName:@"Zapfino" size:25]; 37 | label.textColor = M80RGB(0xFF9F00); 38 | label.shadowColor = [UIColor grayColor]; 39 | label.shadowOffset= CGSizeMake(1, 1); 40 | label.shadowBlur = 1; 41 | 42 | label.frame = CGRectInset(self.view.bounds,20,20); 43 | 44 | [self.view addSubview:label]; 45 | } 46 | 47 | - (void)didReceiveMemoryWarning 48 | { 49 | [super didReceiveMemoryWarning]; 50 | } 51 | 52 | 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /OCDemo/Classes/CustomTextViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // CustomTextViewController.h 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 5/21/14. 6 | // Copyright (c) 2014 www.xiangwangfeng.com. All rights reserved. 7 | // 8 | 9 | #import "BaseLabelViewController.h" 10 | 11 | @interface CustomTextViewController : BaseLabelViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /OCDemo/Classes/CustomTextViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // CustomTextViewController.m 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 5/21/14. 6 | // Copyright (c) 2014 www.xiangwangfeng.com. All rights reserved. 7 | // 8 | 9 | #import "CustomTextViewController.h" 10 | #import "M80AttributedLabel.h" 11 | 12 | @interface CustomTextViewController () 13 | 14 | @end 15 | 16 | @implementation CustomTextViewController 17 | 18 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 19 | { 20 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 21 | if (self) { 22 | // Custom initialization 23 | } 24 | return self; 25 | } 26 | 27 | - (void)viewDidLoad 28 | { 29 | [super viewDidLoad]; 30 | 31 | self.title = @"Custom Text"; 32 | 33 | NSArray *fonts = @[[UIFont systemFontOfSize:12],[UIFont systemFontOfSize:13],[UIFont systemFontOfSize:17],[UIFont systemFontOfSize:25]]; 34 | NSArray *colors= @[M80RGB(0x000000),M80RGB(0x0000FF),M80RGB(0x00FF00),M80RGB(0xFF0000)]; 35 | 36 | 37 | M80AttributedLabel *label = [[M80AttributedLabel alloc]initWithFrame:CGRectZero]; 38 | 39 | NSString *plainText = @"The release of iOS 7 brings a lot of new tools to the table for developers."; 40 | NSArray *components = [plainText componentsSeparatedByString:@" "]; 41 | for (NSString *text in components) 42 | { 43 | NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc]initWithString:text]; 44 | NSInteger index = arc4random() % 4; 45 | [attributedText m80_setFont:[fonts objectAtIndex:index]]; 46 | [attributedText m80_setTextColor:[colors objectAtIndex:index]]; 47 | 48 | [label appendAttributedText:attributedText]; 49 | [label appendText:@" "]; 50 | } 51 | label.frame = CGRectInset(self.view.bounds,20,20); 52 | 53 | [self.view addSubview:label]; 54 | 55 | } 56 | 57 | - (void)didReceiveMemoryWarning 58 | { 59 | [super didReceiveMemoryWarning]; 60 | // Dispose of any resources that can be recreated. 61 | } 62 | 63 | @end 64 | -------------------------------------------------------------------------------- /OCDemo/Classes/DemoTableViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // DemoTableViewController.h 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 4/21/14. 6 | // Copyright (c) 2014 www.xiangwangfeng.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface DemoTableViewController : UITableViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /OCDemo/Classes/DemoTableViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // DemoTableViewController.m 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 4/21/14. 6 | // Copyright (c) 2014 www.xiangwangfeng.com. All rights reserved. 7 | // 8 | 9 | #import "DemoTableViewController.h" 10 | 11 | @interface TableItem : NSObject 12 | @property (nonatomic,strong) NSString *title; 13 | @property (nonatomic,strong) NSString *subTitle; 14 | @property (nonatomic,strong) NSString *vcName; 15 | @end 16 | 17 | @implementation TableItem 18 | + (TableItem *)itemWithTitle:(NSString *)title 19 | subTitle:(NSString *)subTitle 20 | vcName:(NSString *)vcName 21 | { 22 | TableItem *instance = [[TableItem alloc]init]; 23 | instance.title = title; 24 | instance.subTitle = subTitle; 25 | instance.vcName= vcName; 26 | return instance; 27 | } 28 | @end 29 | 30 | @interface DemoTableViewController () 31 | @property (nonatomic,strong) NSArray *items; 32 | @end 33 | 34 | @implementation DemoTableViewController 35 | 36 | - (void)viewDidLoad 37 | { 38 | [super viewDidLoad]; 39 | 40 | self.title = @"Demo"; 41 | self.navigationController.view.backgroundColor = [UIColor whiteColor]; 42 | 43 | _items = @[[TableItem itemWithTitle:@"Basic" 44 | subTitle:@"How to create a simple M80AttributedLabel" 45 | vcName:@"BasicAttributedLabelViewController"], 46 | 47 | 48 | [TableItem itemWithTitle:@"Customizing Text" 49 | subTitle:@"How to use NSAttributedString" 50 | vcName:@"CustomTextViewController"], 51 | 52 | [TableItem itemWithTitle:@"Links" 53 | subTitle:@"Automatic and explicit Links" 54 | vcName:@"LinksViewController"], 55 | 56 | [TableItem itemWithTitle:@"Images" 57 | subTitle:@"How to display images using M80AttributedLabel" 58 | vcName:@"ImagesViewController"], 59 | 60 | [TableItem itemWithTitle:@"LongText" 61 | subTitle:@"Performance for displaying long text" 62 | vcName:@"LongTextViewController"], 63 | 64 | [TableItem itemWithTitle:@"Attachment" 65 | subTitle:@"Add UIView as attachment instead of UIImage" 66 | vcName:@"AttachmentViewController"], 67 | 68 | [TableItem itemWithTitle:@"LineBreakMode" 69 | subTitle:@"Different line break modes" 70 | vcName:@"LineBreakModeViewController"], 71 | 72 | [TableItem itemWithTitle:@"TextAlignment" 73 | subTitle:@"Different test alignments" 74 | vcName:@"TextAlignmentViewController"], 75 | 76 | [TableItem itemWithTitle:@"TableViewCell" 77 | subTitle:@"AttributedLabel in tableviewcell" 78 | vcName:@"TextTableViewController"], 79 | 80 | ]; 81 | } 82 | 83 | - (void)didReceiveMemoryWarning 84 | { 85 | [super didReceiveMemoryWarning]; 86 | } 87 | 88 | #pragma mark - Table view data source 89 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 90 | { 91 | return 1; 92 | } 93 | 94 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 95 | { 96 | return [_items count]; 97 | } 98 | 99 | 100 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 101 | { 102 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"test_demo_cell"]; 103 | if (cell == nil) 104 | { 105 | cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle 106 | reuseIdentifier:@"test_demo_cell"]; 107 | } 108 | TableItem *item = [_items objectAtIndex:[indexPath row]]; 109 | cell.textLabel.text = item.title; 110 | cell.detailTextLabel.text = item.subTitle; 111 | return cell; 112 | } 113 | 114 | 115 | 116 | #pragma mark - Table view delegate 117 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 118 | { 119 | 120 | TableItem *item = [_items objectAtIndex:[indexPath row]]; 121 | NSString *vcName= [item vcName]; 122 | UIViewController *controller = [[NSClassFromString(vcName) alloc] init]; 123 | controller.title = [item title]; 124 | [self.navigationController pushViewController:controller animated:YES]; 125 | } 126 | 127 | 128 | @end 129 | -------------------------------------------------------------------------------- /OCDemo/Classes/DemoTableViewController.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 | -------------------------------------------------------------------------------- /OCDemo/Classes/ImagesViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ImagesViewController.h 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 5/21/14. 6 | // Copyright (c) 2014 www.xiangwangfeng.com. All rights reserved. 7 | // 8 | 9 | #import "BaseLabelViewController.h" 10 | 11 | @interface ImagesViewController : BaseLabelViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /OCDemo/Classes/ImagesViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ImagesViewController.m 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 5/21/14. 6 | // Copyright (c) 2014 www.xiangwangfeng.com. All rights reserved. 7 | // 8 | 9 | #import "ImagesViewController.h" 10 | #import "M80AttributedLabel.h" 11 | 12 | @interface ImagesViewController () 13 | 14 | @end 15 | 16 | @implementation ImagesViewController 17 | 18 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 19 | { 20 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 21 | if (self) { 22 | // Custom initialization 23 | } 24 | return self; 25 | } 26 | 27 | - (void)viewDidLoad 28 | { 29 | [super viewDidLoad]; 30 | 31 | self.title = @"Images"; 32 | 33 | M80AttributedLabel *label = [[M80AttributedLabel alloc]initWithFrame:CGRectZero]; 34 | label.lineSpacing = 5.0; 35 | 36 | [label appendImage:[UIImage imageNamed:@"avatar" 37 | ] maxSize:CGSizeMake(40, 40) 38 | margin:UIEdgeInsetsZero 39 | alignment:M80ImageAlignmentBottom]; 40 | 41 | NSString *text = @"say:\n有人问一位登山家为什么要去登山——谁都知道登山这件事既危险,又没什么实际的好处。[haha][haha][haha][haha]他回答道:“因为那座山峰在那里。”我喜欢这个答案,因为里面包含着幽默感——明明是自己想要登山,偏说是山在那里使他心里痒痒。除此之外,我还喜欢这位登山家干的事,没来由地往悬崖上爬。[haha][haha][haha]它会导致肌肉疼痛,还要冒摔出脑子的危险,所以一般人尽量避免爬山。[haha][haha][haha]用热力学的角度来看,这是个反熵的现象,所发趋害避利肯定反熵。"; 42 | 43 | //replace [haha] by image 44 | NSArray *components = [text componentsSeparatedByString:@"[haha]"]; 45 | NSUInteger count = [components count]; 46 | for (NSUInteger i = 0; i < count; i++) 47 | { 48 | [label appendText:[components objectAtIndex:i]]; 49 | if (i != count - 1) 50 | { 51 | [label appendImage:[UIImage imageNamed:@"haha"] 52 | maxSize:CGSizeMake(15, 15) 53 | margin:UIEdgeInsetsZero 54 | alignment:M80ImageAlignmentCenter]; 55 | } 56 | } 57 | 58 | 59 | label.frame = CGRectInset(self.view.bounds,20,20); 60 | 61 | [self.view addSubview:label]; 62 | } 63 | 64 | - (void)didReceiveMemoryWarning 65 | { 66 | [super didReceiveMemoryWarning]; 67 | // Dispose of any resources that can be recreated. 68 | } 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /OCDemo/Classes/LineBreakModeViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // LineBreakModeViewController.h 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 5/21/14. 6 | // Copyright (c) 2014 www.xiangwangfeng.com. All rights reserved. 7 | // 8 | 9 | #import "BaseLabelViewController.h" 10 | 11 | @interface LineBreakModeViewController : BaseLabelViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /OCDemo/Classes/LineBreakModeViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // LineBreakModeViewController.m 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 5/21/14. 6 | // Copyright (c) 2014 www.xiangwangfeng.com. All rights reserved. 7 | // 8 | 9 | #import "LineBreakModeViewController.h" 10 | #import "M80AttributedLabel.h" 11 | 12 | @interface LineBreakModeViewController () 13 | 14 | @end 15 | 16 | @implementation LineBreakModeViewController 17 | 18 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 19 | { 20 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 21 | if (self) { 22 | // Custom initialization 23 | } 24 | return self; 25 | } 26 | 27 | - (void)viewDidLoad 28 | { 29 | [super viewDidLoad]; 30 | 31 | /* 32 | kCTLineBreakByWordWrapping = 0, 33 | kCTLineBreakByCharWrapping = 1, 34 | kCTLineBreakByClipping = 2, 35 | kCTLineBreakByTruncatingHead = 3, 36 | kCTLineBreakByTruncatingTail = 4, 37 | kCTLineBreakByTruncatingMiddle = 5*/ 38 | 39 | self.title = @"LineBreakMode"; 40 | 41 | NSString *textMoreThanTwoLines = @"有关美国的一切,可以用一句话来描述:“Americans business is business”,这句话的意思就是说,那个国家永远是在经商热中,而且永远是一千度的白热。所以你要是看了前文之后以为那里有某种气氛会有助于人立志写作就错了。连我哥哥到了那里都后悔了,觉得不该学逻辑,应当学商科或者计算机。虽然他依旧未证出的逻辑定理,但是看到有钱人豪华的住房,也免不了唠叨几句他对妻儿的责任。"; 42 | 43 | for (NSUInteger i = kCTLineBreakByWordWrapping; 44 | i <= kCTLineBreakByTruncatingMiddle;i++) 45 | { 46 | M80AttributedLabel *label = [[M80AttributedLabel alloc]initWithFrame:CGRectZero]; 47 | label.text = textMoreThanTwoLines; 48 | [label setLineBreakMode:i]; 49 | [label setNumberOfLines:2]; 50 | [label setFrame:CGRectMake(20, 20 + i * 60, self.view.bounds.size.width - 20 * 2, 50)]; 51 | 52 | [label.layer setBorderColor:[UIColor orangeColor].CGColor]; 53 | [label.layer setBorderWidth:1]; 54 | 55 | [self.view addSubview:label]; 56 | 57 | 58 | } 59 | } 60 | 61 | - (void)didReceiveMemoryWarning 62 | { 63 | [super didReceiveMemoryWarning]; 64 | // Dispose of any resources that can be recreated. 65 | } 66 | 67 | 68 | @end 69 | -------------------------------------------------------------------------------- /OCDemo/Classes/LinksViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // LinksViewController.h 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 5/21/14. 6 | // Copyright (c) 2014 www.xiangwangfeng.com. All rights reserved. 7 | // 8 | 9 | #import "BaseLabelViewController.h" 10 | 11 | @interface LinksViewController : BaseLabelViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /OCDemo/Classes/LinksViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // LinksViewController.m 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 5/21/14. 6 | // Copyright (c) 2014 www.xiangwangfeng.com. All rights reserved. 7 | // 8 | 9 | #import "LinksViewController.h" 10 | #import "M80AttributedLabel.h" 11 | 12 | 13 | @interface LinksViewController () 14 | 15 | @end 16 | 17 | @implementation LinksViewController 18 | 19 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 20 | { 21 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 22 | if (self) { 23 | // Custom initialization 24 | } 25 | return self; 26 | } 27 | 28 | - (void)viewDidLoad 29 | { 30 | [super viewDidLoad]; 31 | 32 | self.title = @"Links"; 33 | 34 | M80AttributedLabel *label = [[M80AttributedLabel alloc]initWithFrame:CGRectZero]; 35 | 36 | NSString *text = @"The game which I current play is hearthstone,and its website is www.hearthstone.com.cn"; 37 | NSRange range = [text rangeOfString:@"hearthstone"]; 38 | label.text = text; 39 | [label addCustomLink:[NSValue valueWithRange:range] 40 | forRange:range]; 41 | label.delegate = self; 42 | 43 | 44 | label.frame = CGRectInset(self.view.bounds,20,20); 45 | 46 | [self.view addSubview:label]; 47 | 48 | } 49 | 50 | - (void)m80AttributedLabel:(M80AttributedLabel *)label 51 | clickedOnLink:(id)linkData 52 | { 53 | NSString *message = [NSString stringWithFormat:@"link data is %@:%@",[[linkData class] description],linkData]; 54 | 55 | UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"you click a link" 56 | message:message 57 | preferredStyle:UIAlertControllerStyleAlert]; 58 | UIAlertAction *action = [UIAlertAction actionWithTitle:@"Cancel" 59 | style:UIAlertActionStyleCancel 60 | handler:nil]; 61 | [controller addAction:action]; 62 | [self presentViewController:controller 63 | animated:YES 64 | completion:nil]; 65 | } 66 | 67 | - (void)didReceiveMemoryWarning 68 | { 69 | [super didReceiveMemoryWarning]; 70 | // Dispose of any resources that can be recreated. 71 | } 72 | 73 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 74 | { 75 | NSLog(@"touch view controller"); 76 | } 77 | @end 78 | -------------------------------------------------------------------------------- /OCDemo/Classes/LongTextViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // LongTextViewController.h 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 5/21/14. 6 | // Copyright (c) 2014 www.xiangwangfeng.com. All rights reserved. 7 | // 8 | 9 | #import "BaseLabelViewController.h" 10 | 11 | @interface LongTextViewController : BaseLabelViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /OCDemo/Classes/LongTextViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // LongTextViewController.m 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 5/21/14. 6 | // Copyright (c) 2014 www.xiangwangfeng.com. All rights reserved. 7 | // 8 | 9 | #import "LongTextViewController.h" 10 | #import "M80AttributedLabel.h" 11 | 12 | 13 | 14 | @interface LongTextViewController () 15 | 16 | @end 17 | 18 | @implementation LongTextViewController 19 | 20 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 21 | { 22 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 23 | if (self) { 24 | // Custom initialization 25 | } 26 | return self; 27 | } 28 | 29 | - (void)viewDidLoad 30 | { 31 | [super viewDidLoad]; 32 | 33 | self.title = @"LongText"; 34 | 35 | NSString *path = [[NSBundle mainBundle] pathForResource:@"test" 36 | ofType:@"txt"]; 37 | NSString *content = [NSString stringWithContentsOfFile:path 38 | encoding:NSUTF8StringEncoding 39 | error:nil]; 40 | 41 | M80AttributedLabel *label = [[M80AttributedLabel alloc]initWithFrame:CGRectZero]; 42 | label.lineSpacing = 5.0; 43 | label.paragraphSpacing = 10.0; 44 | label.text = content; 45 | 46 | UIScrollView *scrollView = [[UIScrollView alloc]initWithFrame:self.view.bounds]; 47 | scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 48 | 49 | [scrollView addSubview:label]; 50 | [self.view addSubview:scrollView]; 51 | 52 | CGSize labelSize = [label sizeThatFits:CGSizeMake(CGRectGetWidth(self.view.bounds) - 40, CGFLOAT_MAX)]; 53 | [label setFrame:CGRectMake(20, 10, labelSize.width, labelSize.height)]; 54 | scrollView.contentSize = CGSizeMake(CGRectGetWidth(self.view.bounds), labelSize.height + 20); 55 | 56 | } 57 | 58 | - (void)didReceiveMemoryWarning 59 | { 60 | [super didReceiveMemoryWarning]; 61 | 62 | } 63 | 64 | /* 65 | #pragma mark - Navigation 66 | 67 | // In a storyboard-based application, you will often want to do a little preparation before navigation 68 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 69 | { 70 | // Get the new view controller using [segue destinationViewController]. 71 | // Pass the selected object to the new view controller. 72 | } 73 | */ 74 | 75 | @end 76 | -------------------------------------------------------------------------------- /OCDemo/Classes/TextAlignmentViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // TextAlignmentViewController.h 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 5/21/14. 6 | // Copyright (c) 2014 www.xiangwangfeng.com. All rights reserved. 7 | // 8 | 9 | #import "BaseLabelViewController.h" 10 | 11 | @interface TextAlignmentViewController : BaseLabelViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /OCDemo/Classes/TextAlignmentViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // TextAlignmentViewController.m 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 5/21/14. 6 | // Copyright (c) 2014 www.xiangwangfeng.com. All rights reserved. 7 | // 8 | 9 | #import "TextAlignmentViewController.h" 10 | #import "M80AttributedLabel.h" 11 | 12 | @interface TextAlignmentViewController () 13 | 14 | @end 15 | 16 | @implementation TextAlignmentViewController 17 | 18 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 19 | { 20 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 21 | if (self) { 22 | // Custom initialization 23 | } 24 | return self; 25 | } 26 | 27 | - (void)viewDidLoad 28 | { 29 | [super viewDidLoad]; 30 | 31 | /* 32 | kCTTextAlignmentLeft = 0, 33 | kCTTextAlignmentRight = 1, 34 | kCTTextAlignmentCenter = 2, 35 | kCTTextAlignmentJustified = 3, 36 | kCTTextAlignmentNatural = 4,*/ 37 | 38 | self.title = @"TextAlignment"; 39 | 40 | 41 | NSString *text = @"Hello M80AttributedLabel"; 42 | 43 | for (NSUInteger i = kCTTextAlignmentLeft; 44 | i <= kCTTextAlignmentNatural;i++) 45 | { 46 | M80AttributedLabel *label = [[M80AttributedLabel alloc]initWithFrame:CGRectZero]; 47 | label.text = text; 48 | [label setTextAlignment:i]; 49 | [label setFrame:CGRectMake(20, 20 + i * 60, 280, 25)]; 50 | 51 | [label.layer setBorderColor:[UIColor orangeColor].CGColor]; 52 | [label.layer setBorderWidth:1]; 53 | 54 | [self.view addSubview:label]; 55 | 56 | 57 | } 58 | 59 | } 60 | 61 | - (void)didReceiveMemoryWarning 62 | { 63 | [super didReceiveMemoryWarning]; 64 | // Dispose of any resources that can be recreated. 65 | } 66 | 67 | /* 68 | #pragma mark - Navigation 69 | 70 | // In a storyboard-based application, you will often want to do a little preparation before navigation 71 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 72 | { 73 | // Get the new view controller using [segue destinationViewController]. 74 | // Pass the selected object to the new view controller. 75 | } 76 | */ 77 | 78 | @end 79 | -------------------------------------------------------------------------------- /OCDemo/Classes/TextTableViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // TextTableViewController.h 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 7/10/14. 6 | // Copyright (c) 2014 www.xiangwangfeng.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TextTableViewController : UITableViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /OCDemo/Classes/TextTableViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // TextTableViewController.m 3 | // M80AttributedLabel 4 | // 5 | // Created by amao on 7/10/14. 6 | // Copyright (c) 2014 www.xiangwangfeng.com. All rights reserved. 7 | // 8 | 9 | #import "TextTableViewController.h" 10 | #import "M80AttributedLabel.h" 11 | #import "AutoLayoutTableViewCell.h" 12 | 13 | static dispatch_queue_t shared_queue() 14 | { 15 | static dispatch_queue_t queue = NULL; 16 | if (queue == NULL) 17 | { 18 | queue = dispatch_queue_create("data_source_queue", 0); 19 | } 20 | return queue; 21 | } 22 | 23 | 24 | 25 | @interface Messsage : NSObject 26 | @property (nonatomic,strong) NSString *messageID; 27 | @property (nonatomic,strong) NSString *text; 28 | @property (nonatomic,assign) BOOL autoLayout; 29 | @end 30 | 31 | @implementation Messsage 32 | + (Messsage *)message 33 | { 34 | Messsage *message = [[Messsage alloc]init]; 35 | message.messageID = [[NSUUID UUID] UUIDString]; 36 | message.text = [Messsage ramdomText]; 37 | message.autoLayout= arc4random() % 2 == 0; 38 | return message; 39 | } 40 | 41 | + (NSString *)ramdomText 42 | { 43 | static NSArray *messages = nil; 44 | 45 | if (messages == nil) 46 | { 47 | NSString *path = [[NSBundle mainBundle] pathForResource:@"test" 48 | ofType:@"txt"]; 49 | NSString *content = [[NSString alloc] initWithContentsOfFile:path 50 | encoding:NSUTF8StringEncoding 51 | error:nil]; 52 | NSArray *contentLines = [content componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]]; 53 | 54 | 55 | NSMutableArray *tempMessages = [NSMutableArray array]; 56 | for (NSInteger i = 0; i < 100; i++) 57 | { 58 | NSMutableString *str = [[NSMutableString alloc]init]; 59 | [str appendString:@"M80 says:[haha] [haha] Your magic is Mine.[haha] [haha]"]; 60 | NSInteger line = random() % [contentLines count]; 61 | for (NSInteger j = 0; j < random() % 3; j++) 62 | { 63 | [str appendString:[contentLines objectAtIndex:line]]; 64 | } 65 | [tempMessages addObject:str]; 66 | messages = tempMessages; 67 | } 68 | } 69 | NSInteger count = arc4random() % 100; 70 | return [messages objectAtIndex:count]; 71 | } 72 | @end 73 | 74 | 75 | @interface TextTableViewController () 76 | @property (nonatomic,strong) NSMutableArray *messages; 77 | @property (nonatomic,strong) NSMutableDictionary *cellHeights; 78 | @end 79 | 80 | @implementation TextTableViewController 81 | 82 | - (id)initWithStyle:(UITableViewStyle)style 83 | { 84 | self = [super initWithStyle:style]; 85 | if (self) { 86 | // Custom initialization 87 | } 88 | return self; 89 | } 90 | 91 | - (void)viewDidLoad 92 | { 93 | [super viewDidLoad]; 94 | 95 | self.refreshControl = [[UIRefreshControl alloc]init]; 96 | [self.tableView addSubview:self.refreshControl]; 97 | [self.refreshControl addTarget:self 98 | action:@selector(onRefresh:) 99 | forControlEvents:UIControlEventValueChanged]; 100 | 101 | _messages = [NSMutableArray array]; 102 | _cellHeights = [NSMutableDictionary dictionary]; 103 | 104 | self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]initWithTitle:@"Reload" 105 | style:UIBarButtonItemStyleDone 106 | target:self 107 | action:@selector(onReload:)]; 108 | } 109 | 110 | - (void)didReceiveMemoryWarning 111 | { 112 | [super didReceiveMemoryWarning]; 113 | // Dispose of any resources that can be recreated. 114 | } 115 | 116 | - (void)onRefresh:(id)sender 117 | { 118 | dispatch_async(shared_queue(), ^{ 119 | NSMutableArray *messages = [NSMutableArray array]; 120 | for (NSInteger i = 0; i < 200; i++) 121 | { 122 | Messsage *message = [Messsage message]; 123 | [messages addObject:message]; 124 | } 125 | dispatch_async(dispatch_get_main_queue(), ^{ 126 | [self.messages insertObjects:messages 127 | atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [messages count])]]; 128 | [self.refreshControl endRefreshing]; 129 | [self.tableView reloadData]; 130 | }); 131 | }); 132 | } 133 | 134 | - (void)onReload:(id)sender 135 | { 136 | NSLog(@"begin reload"); 137 | [self.tableView reloadData]; 138 | NSLog(@"end reload %lu",(unsigned long)[_messages count]); 139 | } 140 | 141 | #pragma mark - Table view Helper 142 | - (CGFloat)cellHeight:(Messsage *)message 143 | { 144 | NSString *messageID = message.messageID; 145 | CGFloat height = [[_cellHeights objectForKey:messageID] floatValue]; 146 | if (height == 0) 147 | { 148 | if (message.autoLayout) 149 | { 150 | AutoLayoutTableViewCell *cell = [[[NSBundle mainBundle] loadNibNamed:@"AutoLayoutTableViewCell" 151 | owner:nil 152 | options:nil] lastObject]; 153 | [self updateLabel:cell.autoLayoutLabel 154 | text:message.text]; 155 | CGSize size = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]; 156 | height = size.height + 1; 157 | } 158 | else 159 | { 160 | M80AttributedLabel *label = [[M80AttributedLabel alloc]initWithFrame:CGRectZero]; 161 | [self updateLabel:label 162 | text:message.text]; 163 | CGSize size = [label sizeThatFits:CGSizeMake(self.view.bounds.size.width, CGFLOAT_MAX)]; 164 | height = size.height + 20 + 20; 165 | } 166 | [_cellHeights setObject:@(height) 167 | forKey:messageID]; 168 | } 169 | return height; 170 | } 171 | 172 | 173 | - (void)updateLabel:(M80AttributedLabel *)label 174 | text:(NSString *)text 175 | { 176 | [label setText:@""]; 177 | 178 | NSArray *components = [text componentsSeparatedByString:@"[haha]"]; 179 | NSUInteger count = [components count]; 180 | for (NSUInteger i = 0; i < count; i++) 181 | { 182 | [label appendText:[components objectAtIndex:i]]; 183 | if (i != count - 1) 184 | { 185 | [label appendImage:[UIImage imageNamed:@"haha"] 186 | maxSize:CGSizeMake(13, 13) 187 | margin:UIEdgeInsetsZero 188 | alignment:M80ImageAlignmentCenter]; 189 | } 190 | } 191 | 192 | 193 | } 194 | 195 | #pragma mark - Table view data source 196 | 197 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 198 | { 199 | return 1; 200 | } 201 | 202 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 203 | { 204 | return [_messages count]; 205 | } 206 | 207 | static const NSInteger labelTag = 10; 208 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 209 | { 210 | Messsage *message = [_messages objectAtIndex:[indexPath row]]; 211 | if (message.autoLayout) 212 | { 213 | AutoLayoutTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"auto_message_cell"]; 214 | if (cell == nil) 215 | { 216 | cell = [[[NSBundle mainBundle] loadNibNamed:@"AutoLayoutTableViewCell" 217 | owner:nil 218 | options:nil] lastObject]; 219 | } 220 | [self updateLabel:cell.autoLayoutLabel 221 | text:message.text]; 222 | return cell; 223 | } 224 | else 225 | { 226 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"message_cell"]; 227 | if (cell == nil) 228 | { 229 | cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault 230 | reuseIdentifier:@"message_cell"]; 231 | M80AttributedLabel *label = [[M80AttributedLabel alloc] initWithFrame:CGRectZero]; 232 | [cell.contentView addSubview:label]; 233 | [label setTag:labelTag]; 234 | } 235 | M80AttributedLabel *label = (M80AttributedLabel *)[cell viewWithTag:labelTag]; 236 | [self updateLabel:label 237 | text:message.text]; 238 | return cell; 239 | } 240 | } 241 | 242 | - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath 243 | { 244 | Messsage *message = [_messages objectAtIndex:[indexPath row]]; 245 | if (!message.autoLayout) 246 | { 247 | M80AttributedLabel *label = (M80AttributedLabel *)[cell viewWithTag:labelTag]; 248 | [label setFrame:CGRectMake(25, 20, cell.bounds.size.width - 25 * 2, cell.bounds.size.height - 20 * 2)]; 249 | } 250 | } 251 | 252 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 253 | { 254 | Messsage *message = [_messages objectAtIndex:[indexPath row]]; 255 | return [self cellHeight:message]; 256 | } 257 | 258 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 259 | { 260 | Messsage *message = [_messages objectAtIndex:[indexPath row]]; 261 | 262 | UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"what you select is " 263 | message:message.text 264 | preferredStyle:UIAlertControllerStyleAlert]; 265 | UIAlertAction *action = [UIAlertAction actionWithTitle:@"Cancel" 266 | style:UIAlertActionStyleCancel 267 | handler:nil]; 268 | [controller addAction:action]; 269 | [self presentViewController:controller 270 | animated:YES 271 | completion:nil]; 272 | } 273 | 274 | 275 | 276 | @end 277 | -------------------------------------------------------------------------------- /OCDemo/OCDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /OCDemo/OCDemo.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /OCDemo/OCDemo.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /OCDemo/OCDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // OCDemo 4 | // 5 | // Created by amao on 2016/10/12. 6 | // Copyright © 2016年 NetEase. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /OCDemo/OCDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // OCDemo 4 | // 5 | // Created by amao on 2016/10/12. 6 | // Copyright © 2016年 NetEase. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "DemoTableViewController.h" 11 | 12 | @interface AppDelegate () 13 | 14 | @end 15 | 16 | @implementation AppDelegate 17 | 18 | 19 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 20 | 21 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 22 | DemoTableViewController *demoVC = [[DemoTableViewController alloc]init]; 23 | UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:demoVC]; 24 | self.window.rootViewController = nav; 25 | [self.window makeKeyAndVisible]; 26 | 27 | return YES; 28 | } 29 | 30 | 31 | - (void)applicationWillResignActive:(UIApplication *)application { 32 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 33 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 34 | } 35 | 36 | 37 | - (void)applicationDidEnterBackground:(UIApplication *)application { 38 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 39 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 40 | } 41 | 42 | 43 | - (void)applicationWillEnterForeground:(UIApplication *)application { 44 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 45 | } 46 | 47 | 48 | - (void)applicationDidBecomeActive:(UIApplication *)application { 49 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 50 | } 51 | 52 | 53 | - (void)applicationWillTerminate:(UIApplication *)application { 54 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 55 | } 56 | 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /OCDemo/OCDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | } 43 | ], 44 | "info" : { 45 | "version" : 1, 46 | "author" : "xcode" 47 | } 48 | } -------------------------------------------------------------------------------- /OCDemo/OCDemo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /OCDemo/OCDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /OCDemo/OCDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIRequiredDeviceCapabilities 26 | 27 | armv7 28 | 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /OCDemo/OCDemo/OCDemo.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'M80AttributedLabel' target in the 'M80AttributedLabel' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_4_0 8 | #warning "This project uses features only available in iOS SDK 4.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | 16 | 17 | #define M80RGB(rgbValue) [UIColor \ 18 | colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 \ 19 | green:((float)((rgbValue & 0x00FF00) >> 8))/255.0 \ 20 | blue:((float)(rgbValue & 0x0000FF))/255.0 \ 21 | alpha:1.0] 22 | -------------------------------------------------------------------------------- /OCDemo/OCDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // OCDemo 4 | // 5 | // Created by amao on 2016/10/12. 6 | // Copyright © 2016年 NetEase. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /OCDemo/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | target 'OCDemo' do 5 | pod 'M80AttributedLabel', :path => '../' 6 | 7 | end 8 | -------------------------------------------------------------------------------- /OCDemo/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - M80AttributedLabel (1.9.3) 3 | 4 | DEPENDENCIES: 5 | - M80AttributedLabel (from `../`) 6 | 7 | EXTERNAL SOURCES: 8 | M80AttributedLabel: 9 | :path: "../" 10 | 11 | SPEC CHECKSUMS: 12 | M80AttributedLabel: 362643e3ed8d4c53d779eb8fe74f0ee70432c948 13 | 14 | PODFILE CHECKSUM: c204fac8364187b2bd67bb03850fcbcaad8bfd33 15 | 16 | COCOAPODS: 1.7.0.beta.2 17 | -------------------------------------------------------------------------------- /OCDemo/Pods/Headers/Private/M80AttributedLabel/M80AttributedLabel.h: -------------------------------------------------------------------------------- 1 | ../../../../../M80AttributedLabel/M80AttributedLabel.h -------------------------------------------------------------------------------- /OCDemo/Pods/Headers/Private/M80AttributedLabel/M80AttributedLabelAttachment.h: -------------------------------------------------------------------------------- 1 | ../../../../../M80AttributedLabel/M80AttributedLabelAttachment.h -------------------------------------------------------------------------------- /OCDemo/Pods/Headers/Private/M80AttributedLabel/M80AttributedLabelDefines.h: -------------------------------------------------------------------------------- 1 | ../../../../../M80AttributedLabel/M80AttributedLabelDefines.h -------------------------------------------------------------------------------- /OCDemo/Pods/Headers/Private/M80AttributedLabel/M80AttributedLabelURL.h: -------------------------------------------------------------------------------- 1 | ../../../../../M80AttributedLabel/M80AttributedLabelURL.h -------------------------------------------------------------------------------- /OCDemo/Pods/Headers/Private/M80AttributedLabel/M80AttributedLabelURLDetector.h: -------------------------------------------------------------------------------- 1 | ../../../../../M80AttributedLabel/M80AttributedLabelURLDetector.h -------------------------------------------------------------------------------- /OCDemo/Pods/Headers/Private/M80AttributedLabel/NSMutableAttributedString+M80.h: -------------------------------------------------------------------------------- 1 | ../../../../../M80AttributedLabel/NSMutableAttributedString+M80.h -------------------------------------------------------------------------------- /OCDemo/Pods/Headers/Public/M80AttributedLabel/M80AttributedLabel.h: -------------------------------------------------------------------------------- 1 | ../../../../../M80AttributedLabel/M80AttributedLabel.h -------------------------------------------------------------------------------- /OCDemo/Pods/Headers/Public/M80AttributedLabel/M80AttributedLabelAttachment.h: -------------------------------------------------------------------------------- 1 | ../../../../../M80AttributedLabel/M80AttributedLabelAttachment.h -------------------------------------------------------------------------------- /OCDemo/Pods/Headers/Public/M80AttributedLabel/M80AttributedLabelDefines.h: -------------------------------------------------------------------------------- 1 | ../../../../../M80AttributedLabel/M80AttributedLabelDefines.h -------------------------------------------------------------------------------- /OCDemo/Pods/Headers/Public/M80AttributedLabel/M80AttributedLabelURL.h: -------------------------------------------------------------------------------- 1 | ../../../../../M80AttributedLabel/M80AttributedLabelURL.h -------------------------------------------------------------------------------- /OCDemo/Pods/Headers/Public/M80AttributedLabel/M80AttributedLabelURLDetector.h: -------------------------------------------------------------------------------- 1 | ../../../../../M80AttributedLabel/M80AttributedLabelURLDetector.h -------------------------------------------------------------------------------- /OCDemo/Pods/Headers/Public/M80AttributedLabel/NSMutableAttributedString+M80.h: -------------------------------------------------------------------------------- 1 | ../../../../../M80AttributedLabel/NSMutableAttributedString+M80.h -------------------------------------------------------------------------------- /OCDemo/Pods/Local Podspecs/M80AttributedLabel.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "M80AttributedLabel", 3 | "version": "1.9.3", 4 | "authors": { 5 | "Xiang Wangfeng": "xiangwangfeng@gmail.com" 6 | }, 7 | "homepage": "https://github.com/xiangwangfeng/M80AttributedLabel/", 8 | "summary": "Another attributed label using CoreText", 9 | "source": { 10 | "git": "https://github.com/xiangwangfeng/M80AttributedLabel.git", 11 | "tag": "1.9.3" 12 | }, 13 | "license": "MIT", 14 | "requires_arc": true, 15 | "platforms": { 16 | "ios": "7.0" 17 | }, 18 | "frameworks": [ 19 | "CoreText", 20 | "CoreGraphics", 21 | "QuartzCore" 22 | ], 23 | "source_files": "M80AttributedLabel/*.{h,m}" 24 | } 25 | -------------------------------------------------------------------------------- /OCDemo/Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - M80AttributedLabel (1.9.3) 3 | 4 | DEPENDENCIES: 5 | - M80AttributedLabel (from `../`) 6 | 7 | EXTERNAL SOURCES: 8 | M80AttributedLabel: 9 | :path: "../" 10 | 11 | SPEC CHECKSUMS: 12 | M80AttributedLabel: 362643e3ed8d4c53d779eb8fe74f0ee70432c948 13 | 14 | PODFILE CHECKSUM: c204fac8364187b2bd67bb03850fcbcaad8bfd33 15 | 16 | COCOAPODS: 1.7.0.beta.2 17 | -------------------------------------------------------------------------------- /OCDemo/Pods/Target Support Files/M80AttributedLabel/M80AttributedLabel-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_M80AttributedLabel : NSObject 3 | @end 4 | @implementation PodsDummy_M80AttributedLabel 5 | @end 6 | -------------------------------------------------------------------------------- /OCDemo/Pods/Target Support Files/M80AttributedLabel/M80AttributedLabel-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /OCDemo/Pods/Target Support Files/M80AttributedLabel/M80AttributedLabel.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/M80AttributedLabel 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/M80AttributedLabel" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/M80AttributedLabel" 4 | PODS_BUILD_DIR = ${BUILD_DIR} 5 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 6 | PODS_ROOT = ${SRCROOT} 7 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.. 8 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 9 | SKIP_INSTALL = YES 10 | -------------------------------------------------------------------------------- /OCDemo/Pods/Target Support Files/Pods-OCDemo/Pods-OCDemo-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## M80AttributedLabel 5 | 6 | Copyright (c) 2014 Xiang Wangfeng (http://xiangwangfeng.com) 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | 26 | Generated by CocoaPods - https://cocoapods.org 27 | -------------------------------------------------------------------------------- /OCDemo/Pods/Target Support Files/Pods-OCDemo/Pods-OCDemo-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 | Copyright (c) 2014 Xiang Wangfeng (http://xiangwangfeng.com) 18 | 19 | Permission is hereby granted, free of charge, to any person obtaining a copy 20 | of this software and associated documentation files (the "Software"), to deal 21 | in the Software without restriction, including without limitation the rights 22 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 23 | copies of the Software, and to permit persons to whom the Software is 24 | furnished to do so, subject to the following conditions: 25 | 26 | The above copyright notice and this permission notice shall be included in 27 | all copies or substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 35 | THE SOFTWARE. 36 | 37 | License 38 | MIT 39 | Title 40 | M80AttributedLabel 41 | Type 42 | PSGroupSpecifier 43 | 44 | 45 | FooterText 46 | Generated by CocoaPods - https://cocoapods.org 47 | Title 48 | 49 | Type 50 | PSGroupSpecifier 51 | 52 | 53 | StringsTable 54 | Acknowledgements 55 | Title 56 | Acknowledgements 57 | 58 | 59 | -------------------------------------------------------------------------------- /OCDemo/Pods/Target Support Files/Pods-OCDemo/Pods-OCDemo-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_OCDemo : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_OCDemo 5 | @end 6 | -------------------------------------------------------------------------------- /OCDemo/Pods/Target Support Files/Pods-OCDemo/Pods-OCDemo-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | set -u 4 | set -o pipefail 5 | 6 | if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then 7 | # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy 8 | # frameworks to, so exit 0 (signalling the script phase was successful). 9 | exit 0 10 | fi 11 | 12 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 13 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 14 | 15 | COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}" 16 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 17 | 18 | # Used as a return value for each invocation of `strip_invalid_archs` function. 19 | STRIP_BINARY_RETVAL=0 20 | 21 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 22 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 23 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 24 | 25 | # Copies and strips a vendored framework 26 | install_framework() 27 | { 28 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 29 | local source="${BUILT_PRODUCTS_DIR}/$1" 30 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 31 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 32 | elif [ -r "$1" ]; then 33 | local source="$1" 34 | fi 35 | 36 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 37 | 38 | if [ -L "${source}" ]; then 39 | echo "Symlinked..." 40 | source="$(readlink "${source}")" 41 | fi 42 | 43 | # Use filter instead of exclude so missing patterns don't throw errors. 44 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 45 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 46 | 47 | local basename 48 | basename="$(basename -s .framework "$1")" 49 | binary="${destination}/${basename}.framework/${basename}" 50 | if ! [ -r "$binary" ]; then 51 | binary="${destination}/${basename}" 52 | fi 53 | 54 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 55 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 56 | strip_invalid_archs "$binary" 57 | fi 58 | 59 | # Resign the code if required by the build settings to avoid unstable apps 60 | code_sign_if_enabled "${destination}/$(basename "$1")" 61 | 62 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 63 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 64 | local swift_runtime_libs 65 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) 66 | for lib in $swift_runtime_libs; do 67 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 68 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 69 | code_sign_if_enabled "${destination}/${lib}" 70 | done 71 | fi 72 | } 73 | 74 | # Copies and strips a vendored dSYM 75 | install_dsym() { 76 | local source="$1" 77 | if [ -r "$source" ]; then 78 | # Copy the dSYM into a the targets temp dir. 79 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\"" 80 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}" 81 | 82 | local basename 83 | basename="$(basename -s .framework.dSYM "$source")" 84 | binary="${DERIVED_FILES_DIR}/${basename}.framework.dSYM/Contents/Resources/DWARF/${basename}" 85 | 86 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 87 | if [[ "$(file "$binary")" == *"Mach-O dSYM companion"* ]]; then 88 | strip_invalid_archs "$binary" 89 | fi 90 | 91 | if [[ $STRIP_BINARY_RETVAL == 1 ]]; then 92 | # Move the stripped file into its final destination. 93 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\"" 94 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.framework.dSYM" "${DWARF_DSYM_FOLDER_PATH}" 95 | else 96 | # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing. 97 | touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.framework.dSYM" 98 | fi 99 | fi 100 | } 101 | 102 | # Signs a framework with the provided identity 103 | code_sign_if_enabled() { 104 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 105 | # Use the current code_sign_identitiy 106 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 107 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'" 108 | 109 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 110 | code_sign_cmd="$code_sign_cmd &" 111 | fi 112 | echo "$code_sign_cmd" 113 | eval "$code_sign_cmd" 114 | fi 115 | } 116 | 117 | # Strip invalid architectures 118 | strip_invalid_archs() { 119 | binary="$1" 120 | # Get architectures for current target binary 121 | binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)" 122 | # Intersect them with the architectures we are building for 123 | intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)" 124 | # If there are no archs supported by this binary then warn the user 125 | if [[ -z "$intersected_archs" ]]; then 126 | echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)." 127 | STRIP_BINARY_RETVAL=0 128 | return 129 | fi 130 | stripped="" 131 | for arch in $binary_archs; do 132 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then 133 | # Strip non-valid architectures in-place 134 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1 135 | stripped="$stripped $arch" 136 | fi 137 | done 138 | if [[ "$stripped" ]]; then 139 | echo "Stripped $binary of architectures:$stripped" 140 | fi 141 | STRIP_BINARY_RETVAL=1 142 | } 143 | 144 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 145 | wait 146 | fi 147 | -------------------------------------------------------------------------------- /OCDemo/Pods/Target Support Files/Pods-OCDemo/Pods-OCDemo-resources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | set -u 4 | set -o pipefail 5 | 6 | if [ -z ${UNLOCALIZED_RESOURCES_FOLDER_PATH+x} ]; then 7 | # If UNLOCALIZED_RESOURCES_FOLDER_PATH is not set, then there's nowhere for us to copy 8 | # resources to, so exit 0 (signalling the script phase was successful). 9 | exit 0 10 | fi 11 | 12 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 13 | 14 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt 15 | > "$RESOURCES_TO_COPY" 16 | 17 | XCASSET_FILES=() 18 | 19 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 20 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 21 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 22 | 23 | case "${TARGETED_DEVICE_FAMILY:-}" in 24 | 1,2) 25 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" 26 | ;; 27 | 1) 28 | TARGET_DEVICE_ARGS="--target-device iphone" 29 | ;; 30 | 2) 31 | TARGET_DEVICE_ARGS="--target-device ipad" 32 | ;; 33 | 3) 34 | TARGET_DEVICE_ARGS="--target-device tv" 35 | ;; 36 | 4) 37 | TARGET_DEVICE_ARGS="--target-device watch" 38 | ;; 39 | *) 40 | TARGET_DEVICE_ARGS="--target-device mac" 41 | ;; 42 | esac 43 | 44 | install_resource() 45 | { 46 | if [[ "$1" = /* ]] ; then 47 | RESOURCE_PATH="$1" 48 | else 49 | RESOURCE_PATH="${PODS_ROOT}/$1" 50 | fi 51 | if [[ ! -e "$RESOURCE_PATH" ]] ; then 52 | cat << EOM 53 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. 54 | EOM 55 | exit 1 56 | fi 57 | case $RESOURCE_PATH in 58 | *.storyboard) 59 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 60 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 61 | ;; 62 | *.xib) 63 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 64 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 65 | ;; 66 | *.framework) 67 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 68 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 69 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 70 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 71 | ;; 72 | *.xcdatamodel) 73 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true 74 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" 75 | ;; 76 | *.xcdatamodeld) 77 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true 78 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" 79 | ;; 80 | *.xcmappingmodel) 81 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true 82 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" 83 | ;; 84 | *.xcassets) 85 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" 86 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") 87 | ;; 88 | *) 89 | echo "$RESOURCE_PATH" || true 90 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" 91 | ;; 92 | esac 93 | } 94 | 95 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 96 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 97 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then 98 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 99 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 100 | fi 101 | rm -f "$RESOURCES_TO_COPY" 102 | 103 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "${XCASSET_FILES:-}" ] 104 | then 105 | # Find all other xcassets (this unfortunately includes those of path pods and other targets). 106 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) 107 | while read line; do 108 | if [[ $line != "${PODS_ROOT}*" ]]; then 109 | XCASSET_FILES+=("$line") 110 | fi 111 | done <<<"$OTHER_XCASSETS" 112 | 113 | if [ -z ${ASSETCATALOG_COMPILER_APPICON_NAME+x} ]; then 114 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 115 | else 116 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" --app-icon "${ASSETCATALOG_COMPILER_APPICON_NAME}" --output-partial-info-plist "${TARGET_TEMP_DIR}/assetcatalog_generated_info_cocoapods.plist" 117 | fi 118 | fi 119 | -------------------------------------------------------------------------------- /OCDemo/Pods/Target Support Files/Pods-OCDemo/Pods-OCDemo.debug.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 2 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/M80AttributedLabel" 3 | LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/M80AttributedLabel" 4 | OTHER_LDFLAGS = $(inherited) -ObjC -l"M80AttributedLabel" -framework "CoreGraphics" -framework "CoreText" -framework "QuartzCore" 5 | PODS_BUILD_DIR = ${BUILD_DIR} 6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 8 | PODS_ROOT = ${SRCROOT}/Pods 9 | -------------------------------------------------------------------------------- /OCDemo/Pods/Target Support Files/Pods-OCDemo/Pods-OCDemo.release.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 2 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/M80AttributedLabel" 3 | LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/M80AttributedLabel" 4 | OTHER_LDFLAGS = $(inherited) -ObjC -l"M80AttributedLabel" -framework "CoreGraphics" -framework "CoreText" -framework "QuartzCore" 5 | PODS_BUILD_DIR = ${BUILD_DIR} 6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 8 | PODS_ROOT = ${SRCROOT}/Pods 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | M80AttributedLabel 2 | ================== 3 | 4 | 5 | Another attributed label using CoreText [中文版本](./Documents/README.md) 6 | 7 | 8 | # Features 9 | * Multi-line Rich Text Display 10 | * Auto Link Detection and Custom Links Supported 11 | * Embedding Image and Custom Views 12 | * Following Properties Supported: 13 | * `font` 14 | * `textColor` 15 | * `highlightColor` 16 | * `linkColor` 17 | * `underLineForLink` 18 | * `numbersOfLines` (Truncates Last Line Supported) 19 | * `textAlignment` 20 | * `lineBreakMode` 21 | * `lineSpacing` 22 | * `paragraphSpacing` 23 | * `shadowColor` 24 | * `shadowOffset` 25 | * `shadowBlur` 26 | 27 | 28 | 29 | # System Requirement 30 | * iOS 7.0 or later 31 | * ARC required 32 | 33 | # Installation 34 | ### Podfile 35 | ```ruby 36 | pod 'M80AttributedLabel' 37 | ``` 38 | ### Manually 39 | * `git clone https://github.com/xiangwangfeng/M80AttributedLabel.git` 40 | * Copy files in `Class/M80AttributedLabel` to your project 41 | * Add `CoreText.framework` to your target 42 | 43 | # Usage 44 | 45 | ## Basic 46 | 47 | ```objc 48 | 49 | M80AttributedLabel *label = [[M80AttributedLabel alloc]initWithFrame:CGRectZero]; 50 | 51 | label.text = @"Hello M80AttributedLabel"; 52 | label.font = [UIFont fontWithName:@"Zapfino" size:25]; 53 | label.textColor = M80RGB(0xFF9F00); 54 | label.shadowColor = [UIColor grayColor]; 55 | label.shadowOffset= CGSizeMake(1, 1); 56 | label.shadowBlur = 1; 57 | 58 | label.frame = CGRectInset(self.view.bounds,20,20); 59 | 60 | [self.view addSubview:label]; 61 | 62 | ``` 63 | 64 | 65 | 66 | ## Link 67 | 68 | ```objc 69 | 70 | M80AttributedLabel *label = [[M80AttributedLabel alloc]initWithFrame:CGRectZero]; 71 | 72 | NSString *text = @"The game which I current play is hearthstone,and its website is www.hearthstone.com.cn"; 73 | NSRange range = [text rangeOfString:@"hearthstone"]; 74 | label.text = text; 75 | [label addCustomLink:[NSValue valueWithRange:range] 76 | forRange:range]; 77 | label.delegate = self; 78 | 79 | label.frame = CGRectInset(self.view.bounds,20,20); 80 | 81 | [self.view addSubview:label]; 82 | 83 | 84 | ``` 85 | 86 | 87 | 88 | 89 | ## Image 90 | 91 | ```objc 92 | 93 | 94 | M80AttributedLabel *label = [[M80AttributedLabel alloc]initWithFrame:CGRectZero]; 95 | label.lineSpacing = 5.0; 96 | 97 | [label appendImage:[UIImage imageNamed:@"avatar"] 98 | maxSize:CGSizeMake(40, 40) 99 | margin:UIEdgeInsetsZero 100 | alignment:M80ImageAlignmentBottom]; 101 | 102 | NSString *text = @"say:\n有人问一位登山家为什么要去登山——谁都知道登山这件事既危险,又没什么实际的好处。[haha][haha][haha][haha]他回答道:“因为那座山峰在那里。”我喜欢这个答案,因为里面包含着幽默感——明明是自己想要登山,偏说是山在那里使他心里痒痒。除此之外,我还喜欢这位登山家干的事,没来由地往悬崖上爬。[haha][haha][haha]它会导致肌肉疼痛,还要冒摔出脑子的危险,所以一般人尽量避免爬山。[haha][haha][haha]用热力学的角度来看,这是个反熵的现象,所发趋害避利肯定反熵。"; 103 | 104 | //replace [haha] by image 105 | NSArray *components = [text componentsSeparatedByString:@"[haha]"]; 106 | NSUInteger count = [components count]; 107 | for (NSUInteger i = 0; i < count; i++) 108 | { 109 | [label appendText:[components objectAtIndex:i]]; 110 | if (i != count - 1) 111 | { 112 | [label appendImage:[UIImage imageNamed:@"haha"] 113 | maxSize:CGSizeMake(15, 15) 114 | margin:UIEdgeInsetsZero 115 | alignment:M80ImageAlignmentCenter]; 116 | } 117 | } 118 | 119 | label.frame = CGRectInset(self.view.bounds,20,20); 120 | [self.view addSubview:label]; 121 | 122 | 123 | ``` 124 | 125 | 126 | 127 | ## Attachemnt 128 | 129 | ```objc 130 | 131 | M80AttributedLabel *label = [[M80AttributedLabel alloc]initWithFrame:CGRectZero]; 132 | 133 | for (NSInteger i = 0; i < 3; i++) 134 | { 135 | [label appendText:@"Click the icon to fire event"]; 136 | 137 | UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; 138 | button setBackgroundImage:[UIImage imageNamed:@"play"] forState:UIControlStateNormal]; 139 | [button addTarget:self 140 | action:@selector(buttonClicked:) 141 | forControlEvents:UIControlEventTouchUpInside]; 142 | [button setBounds:CGRectMake(0, 0, 30, 30)]; 143 | [button setTag:i]; 144 | [label appendView:button]; 145 | 146 | [label appendText:@"\n\n\n"]; 147 | } 148 | 149 | 150 | label.frame = CGRectInset(self.view.bounds,20,20); 151 | [self.view addSubview:label]; 152 | 153 | ``` 154 | 155 | 156 | 157 | # Contact 158 | * https://github.com/xiangwangfeng 159 | * xiangwangfeng@gmail.com 160 | * http://weibo.com/epmao 161 | 162 | [Apache]: http://www.apache.org/licenses/LICENSE-2.0 163 | [MIT]: http://www.opensource.org/licenses/mit-license.php 164 | [GPL]: http://www.gnu.org/licenses/gpl.html 165 | [BSD]: http://opensource.org/licenses/bsd-license.php 166 | 167 | # License 168 | 169 | M80AttributedLabel is available under the [MIT license][MIT]. See the LICENSE file for more info. 170 | -------------------------------------------------------------------------------- /Resource/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangwangfeng/M80AttributedLabel/9b3431f1094f48b77e505697fb31e714fa99b830/Resource/avatar.png -------------------------------------------------------------------------------- /Resource/haha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangwangfeng/M80AttributedLabel/9b3431f1094f48b77e505697fb31e714fa99b830/Resource/haha.png -------------------------------------------------------------------------------- /Resource/play@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangwangfeng/M80AttributedLabel/9b3431f1094f48b77e505697fb31e714fa99b830/Resource/play@2x.png -------------------------------------------------------------------------------- /Resource/test.txt: -------------------------------------------------------------------------------- 1 | 有人问一位登山家为什么要去登山——谁都知道登山这件事既危险,又没什么实际的好处,他回答道:“因为那座山峰在那里。”我喜欢这个答案,因为里面包含着幽默感——明明是自己想要登山,偏说是山在那里使他心里痒痒。除此之外,我还喜欢这位登山家干的事,没来由地往悬崖上爬。它会导致肌肉疼痛,还要冒摔出脑子的危险,所以一般人尽量避免爬山。用热力学的角度来看,这是个反熵的现象,所发趋害避利肯定反熵。"," 2 | 3 |   现在把登山和写作相提并论,势必要招致反对。这是因为最近十年来中国有过小说热、诗歌热、文化热,无论哪一种热都会导致大量的人投身写作,别人常把我看成此类人士中的一个,并且告诫我说,现在都是什么年月了,你还写小说(言下之意是眼下是经商热,我该下海去经商了)?但是我的情形不一样。前三种热发生时,我正在美国念书,丝毫没有受到感染。我们家的家训是不准孩子学文科,一律去学理工。因为这些缘故,立志写作在我身上是个不折不扣的反熵过程。我到现在也弄不明白自己为什么要干这件事,除了它是个反熵过程这一点。 4 | 5 |   有关我立志写作是个反熵过程,还有进一步解释的必要。写作是个笼统的字眼,还要看写什么东西。写畅销小说、爱情小诗等等热门东西,应该列入熵增过程之列。我写的东西一点不热门,不但挣不了钱,有时还要倒贴一些。严肃作家的“严肃”二字,就该做如此理解。据我所知,这世界上有名的严肃作家,大多是凑合也算不上。这样说明了以后,大家都能明白我确实在一个反熵过程中。 6 | 7 |   我父亲不让我们学文科,理由显而易见。在我们成长的时代里,老舍跳了太平湖,胡风关了临狱,王实味被枪毙了。以前还有金圣叹砍脑壳等等实例。当然,他老人家也是屋内饮酒,门外劝水的人,自己也是个文科的教授,但是他坦白地承认自己择术不正,不足为训。我们兄弟姐妹五个就范此全学了理工科,只我哥哥例外。考虑到我父母脾气暴躁、吼声如雷,你得说这种选择是个熵增过程。而我哥哥那个例外是这么发生的:七八年考大学时,我哥哥是北京木城漳煤矿最强壮的青年矿工,吼起来比我爸爸音量还要大。无论是动手揍他,还是朝他吼叫,我爸爸自己都挺不好意思,所以就任凭他去学了哲学:在罗辑学界的泰斗沈有鼎先生的门下当了研究生。考虑到符号逻辑是个极专门的学科(这是从外行人看不懂得逻辑文章来说),它和理工科差不太多的。从以上的叙述,你可以弄明白我父亲的意思。他希望我们每个人都学一种外行人弄不懂而又是有功世道的专业,平平安安地度过一生。我父亲一生坎坷,他又最爱我们,这样的安排在他看来最自然不过。 8 | 9 |   我自己的情形是这样的:从小到大,身体不算强壮,吼起来音量也不够大,所以一直本分为人。尽管如此,我身上总有一股要写小说的危险情绪。插队的时候,我遇上一个很坏的家伙(他还是我们的领导,属于在我国这个社会里少数坏干部之列),我就编了一个故事,描写他从尾骨开始一寸寸变成了一条驴,并且把它写出来,以泄心头之愤。后来读了一些书,我现卡夫卡也写了个类似的故事,搞得我很不好意思。还有一个故事,女主人公长了蝙蝠的翅膀,并且头发是绿色的,生活在水下。这些二十岁前的作品我都烧掉了。在此一提是要说明这种危险倾向的由来。后来我一直抑制着这种倾向,念完了本科,到美国去留学。我哥哥也念完了硕士,也到美国去留学。我在那边又开始写小说,这种危险的倾向再也不能抑制了。 10 | 11 |   在美国时,我父亲去世了。回想他让我们读理科的事,觉得和美国发生的事不是一个逻辑。这让我想起了前苏联元帅图哈切夫斯基对大音乐家萧斯塔科奇说的话来:“我小的时候,很有音乐天才。只可惜我父亲没钱给我买把小提琴!假如有了那把小提琴,我现在就坐在你的乐池里。”这段话乍看不明其意,需要我提示一句:这次对话发生在苏联的三年代,说宛了没多久,图元帅就一命呜呼。那年头专毙元帅将军,不大毙小提琴手。文化革命里跳楼下吊的却是文人居多。我父亲在世时,一心一意地要给我们每人都弄把小提琴。这把小提琴就是理工农医任一门,只有文科不在其内,这和美国发生的事不一样,但是结论还是同一个——我该去干点别的,不该写小说。 12 | 13 |   有关美国的一切,可以用一句话来描述:“Americans business is business”,这句话的意思就是说,那个国家永远是在经商热中,而且永远是一千度的白热。所以你要是看了前文之后以为那里有某种气氛会有助于人立志写作就错了。连我哥哥到了那里都后悔了,觉得不该学逻辑,应当学商科或者计算机。虽然他依旧未证出的逻辑定理,但是看到有钱人豪华的住房,也免不了唠叨几句他对妻儿的责任。 14 | 15 |   在美国有很强大的力是促使人去挣钱,比方说洋房,有些只有一片小草坪,有的有几百亩草坪,有的有几千亩草坪,所以仅就住房一项,就能产生无穷无尽的挣钱的动力。再比方说汽车,有无穷的档次和价格。你要是真有钱,可以考虑把肯尼边遇刺时坐的汽车买来坐。还有人买下了前苏联的战斗机,驾着飞上天。在那个社会里,没有人受得了自己的孩子对同伴说:我爸爸穷。我要是有孩子,现在也准在那里挣钱。而写书在那里也不是个挣钱的行当,不信你到美国书店里看看,各种各样的书涨了架子,和超级市场里陈列的卫生纸一样多——假如有人出售苦心积虑一页页写出的卫生纸,肯定不是好行当。除此之外,还有好多人的书没有上架,窝在他自己的家里。我没有孩子,也不准备要。作为中国人,我是个极少见的现象。但是人有一张脸,树有一张皮,别人都有钱挣,自己却在干可疑的勾当,脸面上也过不去。 16 | 17 |   在美国时,有一次和一位华人教授聊天,他说他女儿很有出息,放着哈佛大学人类学系奖学金不要,自费去念一般的大学的lawschool如此反潮流,真不愧是书香门第。其实这是舍小利而趋大利,受小害而避大害。不信你去问问律师挣多少钱,人类学家又挣多少钱。和我聊天的这位教授是个大学问家,特立独行之辈。一谈到了儿女,好像也不大特立独行了。 18 | 19 |   说完了美国、苏联,就该谈谈自己。到现在为止,我写了八年小说,也出了几本书,但是大家没怎么看到。除此之外,我还常收到谩骂性的退稿信,这时我总善意地想:写信的人准是领导那里挨了骂,找我撒气。提起王小波,大家准会想到宋朝的四川拉杆子的那一位,想不起我身上。我还在反熵过程中。顺便说一句,人类的存在,文明的发展就是个反熵过程,但是这是说人类。具体说到自己,我的行为依旧无法解释。再顺便说一句,处于反熵过程中,绝不只是我一个人。在美国,我遇上过支起摊来卖托洛斯基、格瓦拉、毛主席等人的书的家伙,我要和他说话,他先问我怕不怕联帮调查局——别的例子还很多。在这些人身上,你就看不到水往低处流、苹果掉下地,狼把兔子吃掉的宏大的过程,看到的现象,相当于水往山上流,苹果飞上天,兔子吃掉狼。我还可以说,光有熵增现象不成。举例言之,大家都顺着一个自然的方向往下溜,最后准会在个低洼的地方汇齐,挤在一起像粪缸里的蛆。但是这也不能解释我的行为。我的行为是不能解释的,假如你把熵增现象看成金科玉律的话。 20 | 21 |   当然,如果硬要我用一句话直截了当地回答这个问题,那就是:我相信我自己有文学才能,我应该做这件事。但是这句话正如一个嫌疑犯说自己没杀人一样不可信。所以信不信由你罢 22 | 23 | PS:为了测试,加个链接进去:http://www.xiangwangfeng.com -------------------------------------------------------------------------------- /SwiftDemo/Classes/AttachmentViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AttachmentViewController.swift 3 | // SwiftDemo 4 | // 5 | // Created by amao on 2016/10/12. 6 | // Copyright © 2016年 amao. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class AttachmentViewController: BaseViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | 16 | self.title = "Attachment" 17 | 18 | let label = M80AttributedLabel() 19 | 20 | for i in 0..<3 { 21 | label.appendText("Click the icon to fire event") 22 | 23 | let button = UIButton(type: .custom) 24 | button.setBackgroundImage(UIImage(named:"play"), for: .normal) 25 | button.addTarget(self, action: #selector(buttonClicked(_:)), for: .touchUpInside) 26 | button.bounds = CGRect.init(x: 0, y: 0, width: 30, height: 30) 27 | button.tag = i 28 | label.append(button) 29 | label.appendText("\n\n\n") 30 | } 31 | 32 | label.frame = self.view.bounds.insetBy(dx: 20, dy: 20) 33 | self.view.addSubview(label) 34 | } 35 | 36 | override func didReceiveMemoryWarning() { 37 | super.didReceiveMemoryWarning() 38 | } 39 | 40 | @objc func buttonClicked(_ sender : AnyObject) { 41 | if let button = sender as? UIButton { 42 | let message = "button tag is \(button.tag)" 43 | let controller = UIAlertController(title: "you click a button", message: message, preferredStyle: .alert) 44 | let action = UIAlertAction(title: "Cancel", style: .cancel, handler: nil) 45 | controller.addAction(action) 46 | self.present(controller, animated: true, completion: nil) 47 | 48 | } 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /SwiftDemo/Classes/BaseViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BaseViewController.swift 3 | // SwiftDemo 4 | // 5 | // Created by amao on 2016/10/12. 6 | // Copyright © 2016年 amao. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class BaseViewController: UIViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | self.edgesForExtendedLayout = UIRectEdge.init(rawValue: 0) 16 | self.view?.backgroundColor = UIColor.white 17 | } 18 | 19 | override func didReceiveMemoryWarning() { 20 | super.didReceiveMemoryWarning() 21 | // Dispose of any resources that can be recreated. 22 | } 23 | 24 | 25 | /* 26 | // MARK: - Navigation 27 | 28 | // In a storyboard-based application, you will often want to do a little preparation before navigation 29 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 30 | // Get the new view controller using segue.destinationViewController. 31 | // Pass the selected object to the new view controller. 32 | } 33 | */ 34 | 35 | } 36 | -------------------------------------------------------------------------------- /SwiftDemo/Classes/BasicAttributedLabelViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BasicAttributedLabelViewController.swift 3 | // SwiftDemo 4 | // 5 | // Created by amao on 2016/10/12. 6 | // Copyright © 2016年 amao. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class BasicAttributedLabelViewController: BaseViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | 16 | self.title = "Basic" 17 | 18 | let label = M80AttributedLabel() 19 | label.text = "Hello M80AttribtuedLabel" 20 | label.font = UIFont(name: "Zapfino", size: 25) 21 | label.textColor = RGB(0xFF9F00) 22 | label.shadowColor = UIColor.gray 23 | label.shadowBlur = 1 24 | label.frame = self.view.bounds.insetBy(dx: 20, dy: 20) 25 | 26 | self.view.addSubview(label) 27 | } 28 | 29 | override func didReceiveMemoryWarning() { 30 | super.didReceiveMemoryWarning() 31 | // Dispose of any resources that can be recreated. 32 | } 33 | 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /SwiftDemo/Classes/CustomTextViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CustomTextViewController.swift 3 | // SwiftDemo 4 | // 5 | // Created by amao on 2016/10/12. 6 | // Copyright © 2016年 amao. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class CustomTextViewController: BaseViewController { 12 | 13 | let fontSize : [CGFloat] = [12,13,17,25] 14 | let colors = [RGB(0x000000),RGB(0x0000ff),RGB(0x00ff00),RGB(0xff0000)] 15 | 16 | 17 | 18 | override func viewDidLoad() { 19 | super.viewDidLoad() 20 | 21 | self.title = "Custom Text" 22 | 23 | let label = M80AttributedLabel() 24 | let text = "The release of iOS 7 brings a lot of new tools to the table for developers." 25 | let components = text.components(separatedBy: " ") 26 | for component in components { 27 | let index = Int(arc4random() % 4) 28 | let attributedText = NSMutableAttributedString(string: component) 29 | attributedText.m80_setFont(UIFont.systemFont(ofSize: fontSize[index])) 30 | attributedText.m80_setTextColor(colors[index]) 31 | 32 | label.appendAttributedText(attributedText) 33 | label.appendText(" ") 34 | } 35 | 36 | label.frame = self.view.bounds.insetBy(dx: 20, dy: 20) 37 | self.view.addSubview(label) 38 | 39 | } 40 | 41 | override func didReceiveMemoryWarning() { 42 | super.didReceiveMemoryWarning() 43 | 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /SwiftDemo/Classes/DemoTableViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DemoTableViewController.swift 3 | // SwiftDemo 4 | // 5 | // Created by amao on 2016/10/12. 6 | // Copyright © 2016年 amao. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | struct Item { 12 | let title : String 13 | let subTitle : String 14 | let vcName : String 15 | 16 | init(_ title : String, _ subTitle : String, _ vcName : String) { 17 | self.title = title 18 | self.subTitle = subTitle 19 | self.vcName = vcName 20 | } 21 | } 22 | 23 | 24 | 25 | 26 | class DemoTableViewController: UITableViewController { 27 | 28 | let items : [Item] = [Item("Basic","How to create a simple M80AttributedLabel","BasicAttributedLabelViewController"), 29 | Item("Customizing Text","How to use NSAttributedString","CustomTextViewController"), 30 | Item("Links","Automatic and explicit Links","LinksViewController"), 31 | Item("Images","How to display images using M80AttributedLabel","ImagesViewController"), 32 | Item("LongText","Performance for displaying long text","LongTextViewController"), 33 | Item("Attachment","Add UIView as attachment instead of UIImag","AttachmentViewController"), 34 | Item("LineBreakMode","Different line break modes","LineBreakModeViewController"), 35 | Item("TextAlignment","Different test alignments","TextAlignmentViewController")] 36 | 37 | override func viewDidLoad() { 38 | super.viewDidLoad() 39 | self.title = "Demo" 40 | self.navigationController?.view.backgroundColor = UIColor.white 41 | } 42 | 43 | override func didReceiveMemoryWarning() { 44 | super.didReceiveMemoryWarning() 45 | } 46 | 47 | // MARK: - Table view data source 48 | override func numberOfSections(in tableView: UITableView) -> Int { 49 | return 1 50 | } 51 | 52 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 53 | return self.items.count 54 | } 55 | 56 | 57 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 58 | 59 | let identifier = "demo_identifier" 60 | let item = self.items[indexPath.row] 61 | var cell = tableView.dequeueReusableCell(withIdentifier:identifier) 62 | if cell == nil { 63 | cell = UITableViewCell(style: .subtitle, reuseIdentifier: identifier) 64 | } 65 | cell?.textLabel?.text = item.title 66 | cell?.detailTextLabel?.text = item.subTitle 67 | 68 | return cell! 69 | } 70 | 71 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 72 | let item = self.items[indexPath.row] 73 | let name = item.vcName 74 | if let vcClass = ClassByName(name: name) as? UIViewController.Type { 75 | let vc = vcClass.init() 76 | self.navigationController?.pushViewController(vc, animated: true) 77 | } 78 | 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /SwiftDemo/Classes/ImagesViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImagesViewController.swift 3 | // SwiftDemo 4 | // 5 | // Created by amao on 2016/10/12. 6 | // Copyright © 2016年 amao. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ImagesViewController: BaseViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | 16 | self.title = "Images" 17 | 18 | let label = M80AttributedLabel() 19 | label.lineSpacing = 5.0 20 | 21 | 22 | if let image = UIImage(named: "avatar") { 23 | label.append(image, maxSize: CGSize.init(width: 40, height: 40), margin:.zero) 24 | } 25 | 26 | let text = "say:\n有人问一位登山家为什么要去登山——谁都知道登山这件事既危险,又没什么实际的好处。[haha][haha][haha][haha]他回答道:“因为那座山峰在那里。”我喜欢这个答案,因为里面包含着幽默感——明明是自己想要登山,偏说是山在那里使他心里痒痒。除此之外,我还喜欢这位登山家干的事,没来由地往悬崖上爬。[haha][haha][haha]它会导致肌肉疼痛,还要冒摔出脑子的危险,所以一般人尽量避免爬山。[haha][haha][haha]用热力学的角度来看,这是个反熵的现象,所发趋害避利肯定反熵。" 27 | let components = text.components(separatedBy: "[haha]") 28 | let count = components.count 29 | for i in 0.. UIColor { 12 | let r = CGFloat((value & 0xFF0000) >> 16) / 255.0 13 | let g = CGFloat((value & 0x00FF00) >> 8 ) / 255.0 14 | let b = CGFloat((value & 0x0000FF) ) / 255.0 15 | return UIColor(red: r, green: g, blue: b, alpha: 1.0) 16 | } 17 | 18 | func ClassByName(name : String) -> AnyClass? { 19 | 20 | var result : AnyClass? = nil 21 | if let bundle = Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String { 22 | let className = bundle + "." + name 23 | result = NSClassFromString(className) 24 | } 25 | return result 26 | } 27 | 28 | -------------------------------------------------------------------------------- /SwiftDemo/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | target 'SwiftDemo' do 5 | pod ‘M80AttributedLabel’, :path => ‘../’ 6 | 7 | end 8 | -------------------------------------------------------------------------------- /SwiftDemo/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - M80AttributedLabel (1.9.3) 3 | 4 | DEPENDENCIES: 5 | - M80AttributedLabel (from `../`) 6 | 7 | EXTERNAL SOURCES: 8 | M80AttributedLabel: 9 | :path: "../" 10 | 11 | SPEC CHECKSUMS: 12 | M80AttributedLabel: 362643e3ed8d4c53d779eb8fe74f0ee70432c948 13 | 14 | PODFILE CHECKSUM: 6bec8775bfed9535c4243f6946f719b518dd40e7 15 | 16 | COCOAPODS: 1.7.0.beta.2 17 | -------------------------------------------------------------------------------- /SwiftDemo/Pods/Headers/Private/M80AttributedLabel/M80AttributedLabel.h: -------------------------------------------------------------------------------- 1 | ../../../../../M80AttributedLabel/M80AttributedLabel.h -------------------------------------------------------------------------------- /SwiftDemo/Pods/Headers/Private/M80AttributedLabel/M80AttributedLabelAttachment.h: -------------------------------------------------------------------------------- 1 | ../../../../../M80AttributedLabel/M80AttributedLabelAttachment.h -------------------------------------------------------------------------------- /SwiftDemo/Pods/Headers/Private/M80AttributedLabel/M80AttributedLabelDefines.h: -------------------------------------------------------------------------------- 1 | ../../../../../M80AttributedLabel/M80AttributedLabelDefines.h -------------------------------------------------------------------------------- /SwiftDemo/Pods/Headers/Private/M80AttributedLabel/M80AttributedLabelURL.h: -------------------------------------------------------------------------------- 1 | ../../../../../M80AttributedLabel/M80AttributedLabelURL.h -------------------------------------------------------------------------------- /SwiftDemo/Pods/Headers/Private/M80AttributedLabel/M80AttributedLabelURLDetector.h: -------------------------------------------------------------------------------- 1 | ../../../../../M80AttributedLabel/M80AttributedLabelURLDetector.h -------------------------------------------------------------------------------- /SwiftDemo/Pods/Headers/Private/M80AttributedLabel/NSMutableAttributedString+M80.h: -------------------------------------------------------------------------------- 1 | ../../../../../M80AttributedLabel/NSMutableAttributedString+M80.h -------------------------------------------------------------------------------- /SwiftDemo/Pods/Headers/Public/M80AttributedLabel/M80AttributedLabel.h: -------------------------------------------------------------------------------- 1 | ../../../../../M80AttributedLabel/M80AttributedLabel.h -------------------------------------------------------------------------------- /SwiftDemo/Pods/Headers/Public/M80AttributedLabel/M80AttributedLabelAttachment.h: -------------------------------------------------------------------------------- 1 | ../../../../../M80AttributedLabel/M80AttributedLabelAttachment.h -------------------------------------------------------------------------------- /SwiftDemo/Pods/Headers/Public/M80AttributedLabel/M80AttributedLabelDefines.h: -------------------------------------------------------------------------------- 1 | ../../../../../M80AttributedLabel/M80AttributedLabelDefines.h -------------------------------------------------------------------------------- /SwiftDemo/Pods/Headers/Public/M80AttributedLabel/M80AttributedLabelURL.h: -------------------------------------------------------------------------------- 1 | ../../../../../M80AttributedLabel/M80AttributedLabelURL.h -------------------------------------------------------------------------------- /SwiftDemo/Pods/Headers/Public/M80AttributedLabel/M80AttributedLabelURLDetector.h: -------------------------------------------------------------------------------- 1 | ../../../../../M80AttributedLabel/M80AttributedLabelURLDetector.h -------------------------------------------------------------------------------- /SwiftDemo/Pods/Headers/Public/M80AttributedLabel/NSMutableAttributedString+M80.h: -------------------------------------------------------------------------------- 1 | ../../../../../M80AttributedLabel/NSMutableAttributedString+M80.h -------------------------------------------------------------------------------- /SwiftDemo/Pods/Local Podspecs/M80AttributedLabel.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "M80AttributedLabel", 3 | "version": "1.9.3", 4 | "authors": { 5 | "Xiang Wangfeng": "xiangwangfeng@gmail.com" 6 | }, 7 | "homepage": "https://github.com/xiangwangfeng/M80AttributedLabel/", 8 | "summary": "Another attributed label using CoreText", 9 | "source": { 10 | "git": "https://github.com/xiangwangfeng/M80AttributedLabel.git", 11 | "tag": "1.9.3" 12 | }, 13 | "license": "MIT", 14 | "requires_arc": true, 15 | "platforms": { 16 | "ios": "7.0" 17 | }, 18 | "frameworks": [ 19 | "CoreText", 20 | "CoreGraphics", 21 | "QuartzCore" 22 | ], 23 | "source_files": "M80AttributedLabel/*.{h,m}" 24 | } 25 | -------------------------------------------------------------------------------- /SwiftDemo/Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - M80AttributedLabel (1.9.3) 3 | 4 | DEPENDENCIES: 5 | - M80AttributedLabel (from `../`) 6 | 7 | EXTERNAL SOURCES: 8 | M80AttributedLabel: 9 | :path: "../" 10 | 11 | SPEC CHECKSUMS: 12 | M80AttributedLabel: 362643e3ed8d4c53d779eb8fe74f0ee70432c948 13 | 14 | PODFILE CHECKSUM: 6bec8775bfed9535c4243f6946f719b518dd40e7 15 | 16 | COCOAPODS: 1.7.0.beta.2 17 | -------------------------------------------------------------------------------- /SwiftDemo/Pods/Target Support Files/M80AttributedLabel/M80AttributedLabel-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_M80AttributedLabel : NSObject 3 | @end 4 | @implementation PodsDummy_M80AttributedLabel 5 | @end 6 | -------------------------------------------------------------------------------- /SwiftDemo/Pods/Target Support Files/M80AttributedLabel/M80AttributedLabel-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /SwiftDemo/Pods/Target Support Files/M80AttributedLabel/M80AttributedLabel.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/M80AttributedLabel 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/M80AttributedLabel" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/M80AttributedLabel" 4 | PODS_BUILD_DIR = ${BUILD_DIR} 5 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 6 | PODS_ROOT = ${SRCROOT} 7 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.. 8 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 9 | SKIP_INSTALL = YES 10 | -------------------------------------------------------------------------------- /SwiftDemo/Pods/Target Support Files/Pods-SwiftDemo/Pods-SwiftDemo-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## M80AttributedLabel 5 | 6 | Copyright (c) 2014 Xiang Wangfeng (http://xiangwangfeng.com) 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | 26 | Generated by CocoaPods - https://cocoapods.org 27 | -------------------------------------------------------------------------------- /SwiftDemo/Pods/Target Support Files/Pods-SwiftDemo/Pods-SwiftDemo-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 | Copyright (c) 2014 Xiang Wangfeng (http://xiangwangfeng.com) 18 | 19 | Permission is hereby granted, free of charge, to any person obtaining a copy 20 | of this software and associated documentation files (the "Software"), to deal 21 | in the Software without restriction, including without limitation the rights 22 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 23 | copies of the Software, and to permit persons to whom the Software is 24 | furnished to do so, subject to the following conditions: 25 | 26 | The above copyright notice and this permission notice shall be included in 27 | all copies or substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 35 | THE SOFTWARE. 36 | 37 | License 38 | MIT 39 | Title 40 | M80AttributedLabel 41 | Type 42 | PSGroupSpecifier 43 | 44 | 45 | FooterText 46 | Generated by CocoaPods - https://cocoapods.org 47 | Title 48 | 49 | Type 50 | PSGroupSpecifier 51 | 52 | 53 | StringsTable 54 | Acknowledgements 55 | Title 56 | Acknowledgements 57 | 58 | 59 | -------------------------------------------------------------------------------- /SwiftDemo/Pods/Target Support Files/Pods-SwiftDemo/Pods-SwiftDemo-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_SwiftDemo : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_SwiftDemo 5 | @end 6 | -------------------------------------------------------------------------------- /SwiftDemo/Pods/Target Support Files/Pods-SwiftDemo/Pods-SwiftDemo-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | set -u 4 | set -o pipefail 5 | 6 | if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then 7 | # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy 8 | # frameworks to, so exit 0 (signalling the script phase was successful). 9 | exit 0 10 | fi 11 | 12 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 13 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 14 | 15 | COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}" 16 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 17 | 18 | # Used as a return value for each invocation of `strip_invalid_archs` function. 19 | STRIP_BINARY_RETVAL=0 20 | 21 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 22 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 23 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 24 | 25 | # Copies and strips a vendored framework 26 | install_framework() 27 | { 28 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 29 | local source="${BUILT_PRODUCTS_DIR}/$1" 30 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 31 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 32 | elif [ -r "$1" ]; then 33 | local source="$1" 34 | fi 35 | 36 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 37 | 38 | if [ -L "${source}" ]; then 39 | echo "Symlinked..." 40 | source="$(readlink "${source}")" 41 | fi 42 | 43 | # Use filter instead of exclude so missing patterns don't throw errors. 44 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 45 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 46 | 47 | local basename 48 | basename="$(basename -s .framework "$1")" 49 | binary="${destination}/${basename}.framework/${basename}" 50 | if ! [ -r "$binary" ]; then 51 | binary="${destination}/${basename}" 52 | fi 53 | 54 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 55 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 56 | strip_invalid_archs "$binary" 57 | fi 58 | 59 | # Resign the code if required by the build settings to avoid unstable apps 60 | code_sign_if_enabled "${destination}/$(basename "$1")" 61 | 62 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 63 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 64 | local swift_runtime_libs 65 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) 66 | for lib in $swift_runtime_libs; do 67 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 68 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 69 | code_sign_if_enabled "${destination}/${lib}" 70 | done 71 | fi 72 | } 73 | 74 | # Copies and strips a vendored dSYM 75 | install_dsym() { 76 | local source="$1" 77 | if [ -r "$source" ]; then 78 | # Copy the dSYM into a the targets temp dir. 79 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\"" 80 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}" 81 | 82 | local basename 83 | basename="$(basename -s .framework.dSYM "$source")" 84 | binary="${DERIVED_FILES_DIR}/${basename}.framework.dSYM/Contents/Resources/DWARF/${basename}" 85 | 86 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 87 | if [[ "$(file "$binary")" == *"Mach-O dSYM companion"* ]]; then 88 | strip_invalid_archs "$binary" 89 | fi 90 | 91 | if [[ $STRIP_BINARY_RETVAL == 1 ]]; then 92 | # Move the stripped file into its final destination. 93 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\"" 94 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.framework.dSYM" "${DWARF_DSYM_FOLDER_PATH}" 95 | else 96 | # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing. 97 | touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.framework.dSYM" 98 | fi 99 | fi 100 | } 101 | 102 | # Signs a framework with the provided identity 103 | code_sign_if_enabled() { 104 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 105 | # Use the current code_sign_identitiy 106 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 107 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'" 108 | 109 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 110 | code_sign_cmd="$code_sign_cmd &" 111 | fi 112 | echo "$code_sign_cmd" 113 | eval "$code_sign_cmd" 114 | fi 115 | } 116 | 117 | # Strip invalid architectures 118 | strip_invalid_archs() { 119 | binary="$1" 120 | # Get architectures for current target binary 121 | binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)" 122 | # Intersect them with the architectures we are building for 123 | intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)" 124 | # If there are no archs supported by this binary then warn the user 125 | if [[ -z "$intersected_archs" ]]; then 126 | echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)." 127 | STRIP_BINARY_RETVAL=0 128 | return 129 | fi 130 | stripped="" 131 | for arch in $binary_archs; do 132 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then 133 | # Strip non-valid architectures in-place 134 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1 135 | stripped="$stripped $arch" 136 | fi 137 | done 138 | if [[ "$stripped" ]]; then 139 | echo "Stripped $binary of architectures:$stripped" 140 | fi 141 | STRIP_BINARY_RETVAL=1 142 | } 143 | 144 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 145 | wait 146 | fi 147 | -------------------------------------------------------------------------------- /SwiftDemo/Pods/Target Support Files/Pods-SwiftDemo/Pods-SwiftDemo-resources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | set -u 4 | set -o pipefail 5 | 6 | if [ -z ${UNLOCALIZED_RESOURCES_FOLDER_PATH+x} ]; then 7 | # If UNLOCALIZED_RESOURCES_FOLDER_PATH is not set, then there's nowhere for us to copy 8 | # resources to, so exit 0 (signalling the script phase was successful). 9 | exit 0 10 | fi 11 | 12 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 13 | 14 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt 15 | > "$RESOURCES_TO_COPY" 16 | 17 | XCASSET_FILES=() 18 | 19 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 20 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 21 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 22 | 23 | case "${TARGETED_DEVICE_FAMILY:-}" in 24 | 1,2) 25 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" 26 | ;; 27 | 1) 28 | TARGET_DEVICE_ARGS="--target-device iphone" 29 | ;; 30 | 2) 31 | TARGET_DEVICE_ARGS="--target-device ipad" 32 | ;; 33 | 3) 34 | TARGET_DEVICE_ARGS="--target-device tv" 35 | ;; 36 | 4) 37 | TARGET_DEVICE_ARGS="--target-device watch" 38 | ;; 39 | *) 40 | TARGET_DEVICE_ARGS="--target-device mac" 41 | ;; 42 | esac 43 | 44 | install_resource() 45 | { 46 | if [[ "$1" = /* ]] ; then 47 | RESOURCE_PATH="$1" 48 | else 49 | RESOURCE_PATH="${PODS_ROOT}/$1" 50 | fi 51 | if [[ ! -e "$RESOURCE_PATH" ]] ; then 52 | cat << EOM 53 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. 54 | EOM 55 | exit 1 56 | fi 57 | case $RESOURCE_PATH in 58 | *.storyboard) 59 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 60 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 61 | ;; 62 | *.xib) 63 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 64 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 65 | ;; 66 | *.framework) 67 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 68 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 69 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 70 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 71 | ;; 72 | *.xcdatamodel) 73 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true 74 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" 75 | ;; 76 | *.xcdatamodeld) 77 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true 78 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" 79 | ;; 80 | *.xcmappingmodel) 81 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true 82 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" 83 | ;; 84 | *.xcassets) 85 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" 86 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") 87 | ;; 88 | *) 89 | echo "$RESOURCE_PATH" || true 90 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" 91 | ;; 92 | esac 93 | } 94 | 95 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 96 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 97 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then 98 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 99 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 100 | fi 101 | rm -f "$RESOURCES_TO_COPY" 102 | 103 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "${XCASSET_FILES:-}" ] 104 | then 105 | # Find all other xcassets (this unfortunately includes those of path pods and other targets). 106 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) 107 | while read line; do 108 | if [[ $line != "${PODS_ROOT}*" ]]; then 109 | XCASSET_FILES+=("$line") 110 | fi 111 | done <<<"$OTHER_XCASSETS" 112 | 113 | if [ -z ${ASSETCATALOG_COMPILER_APPICON_NAME+x} ]; then 114 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 115 | else 116 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" --app-icon "${ASSETCATALOG_COMPILER_APPICON_NAME}" --output-partial-info-plist "${TARGET_TEMP_DIR}/assetcatalog_generated_info_cocoapods.plist" 117 | fi 118 | fi 119 | -------------------------------------------------------------------------------- /SwiftDemo/Pods/Target Support Files/Pods-SwiftDemo/Pods-SwiftDemo.debug.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 2 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/M80AttributedLabel" 3 | LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/M80AttributedLabel" 4 | OTHER_LDFLAGS = $(inherited) -ObjC -l"M80AttributedLabel" -framework "CoreGraphics" -framework "CoreText" -framework "QuartzCore" 5 | PODS_BUILD_DIR = ${BUILD_DIR} 6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 8 | PODS_ROOT = ${SRCROOT}/Pods 9 | -------------------------------------------------------------------------------- /SwiftDemo/Pods/Target Support Files/Pods-SwiftDemo/Pods-SwiftDemo.release.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 2 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/M80AttributedLabel" 3 | LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/M80AttributedLabel" 4 | OTHER_LDFLAGS = $(inherited) -ObjC -l"M80AttributedLabel" -framework "CoreGraphics" -framework "CoreText" -framework "QuartzCore" 5 | PODS_BUILD_DIR = ${BUILD_DIR} 6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 8 | PODS_ROOT = ${SRCROOT}/Pods 9 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 0FB94F06796F3C9E19E46DEB /* libPods-SwiftDemo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 01D0D40D9991462264CA89E7 /* libPods-SwiftDemo.a */; }; 11 | E40951AE1DAF27E300773E64 /* LineBreakModeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E40951AD1DAF27E300773E64 /* LineBreakModeViewController.swift */; }; 12 | E40951B01DAF2ACC00773E64 /* TextAlignmentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E40951AF1DAF2ACC00773E64 /* TextAlignmentViewController.swift */; }; 13 | E4A331A81DAE0B3D00B59A16 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4A331A71DAE0B3D00B59A16 /* AppDelegate.swift */; }; 14 | E4A331AA1DAE0B3D00B59A16 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4A331A91DAE0B3D00B59A16 /* ViewController.swift */; }; 15 | E4A331AD1DAE0B3D00B59A16 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E4A331AB1DAE0B3D00B59A16 /* Main.storyboard */; }; 16 | E4A331AF1DAE0B3D00B59A16 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E4A331AE1DAE0B3D00B59A16 /* Assets.xcassets */; }; 17 | E4A331B21DAE0B3D00B59A16 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E4A331B01DAE0B3D00B59A16 /* LaunchScreen.storyboard */; }; 18 | E4A331E21DAE0FDD00B59A16 /* DemoTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4A331E11DAE0FDD00B59A16 /* DemoTableViewController.swift */; }; 19 | E4A331E61DAE14CB00B59A16 /* BaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4A331E51DAE14CB00B59A16 /* BaseViewController.swift */; }; 20 | E4D22BBE1DAE166C00EB8F7E /* BasicAttributedLabelViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D22BBD1DAE166C00EB8F7E /* BasicAttributedLabelViewController.swift */; }; 21 | E4D22BC01DAE180100EB8F7E /* CustomTextViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D22BBF1DAE180100EB8F7E /* CustomTextViewController.swift */; }; 22 | E4D22BC91DAE191C00EB8F7E /* Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D22BC81DAE191C00EB8F7E /* Util.swift */; }; 23 | E4D22BCF1DAE203C00EB8F7E /* avatar.png in Resources */ = {isa = PBXBuildFile; fileRef = E4D22BCB1DAE203C00EB8F7E /* avatar.png */; }; 24 | E4D22BD01DAE203C00EB8F7E /* haha.png in Resources */ = {isa = PBXBuildFile; fileRef = E4D22BCC1DAE203C00EB8F7E /* haha.png */; }; 25 | E4D22BD11DAE203C00EB8F7E /* play@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = E4D22BCD1DAE203C00EB8F7E /* play@2x.png */; }; 26 | E4D22BD21DAE203C00EB8F7E /* test.txt in Resources */ = {isa = PBXBuildFile; fileRef = E4D22BCE1DAE203C00EB8F7E /* test.txt */; }; 27 | E4D22BD41DAE227700EB8F7E /* LinksViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D22BD31DAE227700EB8F7E /* LinksViewController.swift */; }; 28 | E4D22BD81DAE315300EB8F7E /* ImagesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D22BD71DAE315300EB8F7E /* ImagesViewController.swift */; }; 29 | E4D22BDA1DAE325500EB8F7E /* AttachmentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D22BD91DAE325500EB8F7E /* AttachmentViewController.swift */; }; 30 | E4D22BDC1DAE348500EB8F7E /* LongTextViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D22BDB1DAE348500EB8F7E /* LongTextViewController.swift */; }; 31 | /* End PBXBuildFile section */ 32 | 33 | /* Begin PBXFileReference section */ 34 | 01D0D40D9991462264CA89E7 /* libPods-SwiftDemo.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-SwiftDemo.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 35 | 4BCEAB4CF3E5C6DDE3B882EA /* Pods-SwiftDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftDemo.release.xcconfig"; path = "Pods/Target Support Files/Pods-SwiftDemo/Pods-SwiftDemo.release.xcconfig"; sourceTree = ""; }; 36 | C43C45C0E63F53F1B14DF04D /* Pods-SwiftDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftDemo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SwiftDemo/Pods-SwiftDemo.debug.xcconfig"; sourceTree = ""; }; 37 | E40951AD1DAF27E300773E64 /* LineBreakModeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LineBreakModeViewController.swift; sourceTree = ""; }; 38 | E40951AF1DAF2ACC00773E64 /* TextAlignmentViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextAlignmentViewController.swift; sourceTree = ""; }; 39 | E4A331A41DAE0B3D00B59A16 /* SwiftDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 40 | E4A331A71DAE0B3D00B59A16 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 41 | E4A331A91DAE0B3D00B59A16 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 42 | E4A331AC1DAE0B3D00B59A16 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 43 | E4A331AE1DAE0B3D00B59A16 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 44 | E4A331B11DAE0B3D00B59A16 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 45 | E4A331B31DAE0B3D00B59A16 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 46 | E4A331CF1DAE0DAE00B59A16 /* SwiftDemo-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SwiftDemo-Bridging-Header.h"; sourceTree = ""; }; 47 | E4A331E11DAE0FDD00B59A16 /* DemoTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DemoTableViewController.swift; sourceTree = ""; }; 48 | E4A331E51DAE14CB00B59A16 /* BaseViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseViewController.swift; sourceTree = ""; }; 49 | E4D22BBD1DAE166C00EB8F7E /* BasicAttributedLabelViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BasicAttributedLabelViewController.swift; sourceTree = ""; }; 50 | E4D22BBF1DAE180100EB8F7E /* CustomTextViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomTextViewController.swift; sourceTree = ""; }; 51 | E4D22BC81DAE191C00EB8F7E /* Util.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Util.swift; sourceTree = ""; }; 52 | E4D22BCB1DAE203C00EB8F7E /* avatar.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = avatar.png; sourceTree = ""; }; 53 | E4D22BCC1DAE203C00EB8F7E /* haha.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = haha.png; sourceTree = ""; }; 54 | E4D22BCD1DAE203C00EB8F7E /* play@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "play@2x.png"; sourceTree = ""; }; 55 | E4D22BCE1DAE203C00EB8F7E /* test.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = test.txt; sourceTree = ""; }; 56 | E4D22BD31DAE227700EB8F7E /* LinksViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinksViewController.swift; sourceTree = ""; }; 57 | E4D22BD71DAE315300EB8F7E /* ImagesViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImagesViewController.swift; sourceTree = ""; }; 58 | E4D22BD91DAE325500EB8F7E /* AttachmentViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AttachmentViewController.swift; sourceTree = ""; }; 59 | E4D22BDB1DAE348500EB8F7E /* LongTextViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LongTextViewController.swift; sourceTree = ""; }; 60 | /* End PBXFileReference section */ 61 | 62 | /* Begin PBXFrameworksBuildPhase section */ 63 | E4A331A11DAE0B3D00B59A16 /* Frameworks */ = { 64 | isa = PBXFrameworksBuildPhase; 65 | buildActionMask = 2147483647; 66 | files = ( 67 | 0FB94F06796F3C9E19E46DEB /* libPods-SwiftDemo.a in Frameworks */, 68 | ); 69 | runOnlyForDeploymentPostprocessing = 0; 70 | }; 71 | /* End PBXFrameworksBuildPhase section */ 72 | 73 | /* Begin PBXGroup section */ 74 | 3427210FF04A2630E4701FC1 /* Pods */ = { 75 | isa = PBXGroup; 76 | children = ( 77 | C43C45C0E63F53F1B14DF04D /* Pods-SwiftDemo.debug.xcconfig */, 78 | 4BCEAB4CF3E5C6DDE3B882EA /* Pods-SwiftDemo.release.xcconfig */, 79 | ); 80 | name = Pods; 81 | sourceTree = ""; 82 | }; 83 | A63A55A60449EAEBC9DC5118 /* Frameworks */ = { 84 | isa = PBXGroup; 85 | children = ( 86 | 01D0D40D9991462264CA89E7 /* libPods-SwiftDemo.a */, 87 | ); 88 | name = Frameworks; 89 | sourceTree = ""; 90 | }; 91 | E4A3319B1DAE0B3D00B59A16 = { 92 | isa = PBXGroup; 93 | children = ( 94 | E4A331A61DAE0B3D00B59A16 /* SwiftDemo */, 95 | E4A331A51DAE0B3D00B59A16 /* Products */, 96 | 3427210FF04A2630E4701FC1 /* Pods */, 97 | A63A55A60449EAEBC9DC5118 /* Frameworks */, 98 | ); 99 | sourceTree = ""; 100 | }; 101 | E4A331A51DAE0B3D00B59A16 /* Products */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | E4A331A41DAE0B3D00B59A16 /* SwiftDemo.app */, 105 | ); 106 | name = Products; 107 | sourceTree = ""; 108 | }; 109 | E4A331A61DAE0B3D00B59A16 /* SwiftDemo */ = { 110 | isa = PBXGroup; 111 | children = ( 112 | E4D22BCA1DAE203C00EB8F7E /* Resource */, 113 | E4A331CD1DAE0BB600B59A16 /* Classes */, 114 | E4A331A71DAE0B3D00B59A16 /* AppDelegate.swift */, 115 | E4A331A91DAE0B3D00B59A16 /* ViewController.swift */, 116 | E4A331AB1DAE0B3D00B59A16 /* Main.storyboard */, 117 | E4A331AE1DAE0B3D00B59A16 /* Assets.xcassets */, 118 | E4A331B01DAE0B3D00B59A16 /* LaunchScreen.storyboard */, 119 | E4A331B31DAE0B3D00B59A16 /* Info.plist */, 120 | ); 121 | path = SwiftDemo; 122 | sourceTree = ""; 123 | }; 124 | E4A331CD1DAE0BB600B59A16 /* Classes */ = { 125 | isa = PBXGroup; 126 | children = ( 127 | E4D22BC31DAE188300EB8F7E /* Util */, 128 | E4A331CF1DAE0DAE00B59A16 /* SwiftDemo-Bridging-Header.h */, 129 | E4A331E11DAE0FDD00B59A16 /* DemoTableViewController.swift */, 130 | E4D22BD71DAE315300EB8F7E /* ImagesViewController.swift */, 131 | E4A331E51DAE14CB00B59A16 /* BaseViewController.swift */, 132 | E4D22BBD1DAE166C00EB8F7E /* BasicAttributedLabelViewController.swift */, 133 | E4D22BBF1DAE180100EB8F7E /* CustomTextViewController.swift */, 134 | E4D22BD31DAE227700EB8F7E /* LinksViewController.swift */, 135 | E4D22BD91DAE325500EB8F7E /* AttachmentViewController.swift */, 136 | E4D22BDB1DAE348500EB8F7E /* LongTextViewController.swift */, 137 | E40951AD1DAF27E300773E64 /* LineBreakModeViewController.swift */, 138 | E40951AF1DAF2ACC00773E64 /* TextAlignmentViewController.swift */, 139 | ); 140 | path = Classes; 141 | sourceTree = SOURCE_ROOT; 142 | }; 143 | E4D22BC31DAE188300EB8F7E /* Util */ = { 144 | isa = PBXGroup; 145 | children = ( 146 | E4D22BC81DAE191C00EB8F7E /* Util.swift */, 147 | ); 148 | path = Util; 149 | sourceTree = ""; 150 | }; 151 | E4D22BCA1DAE203C00EB8F7E /* Resource */ = { 152 | isa = PBXGroup; 153 | children = ( 154 | E4D22BCB1DAE203C00EB8F7E /* avatar.png */, 155 | E4D22BCC1DAE203C00EB8F7E /* haha.png */, 156 | E4D22BCD1DAE203C00EB8F7E /* play@2x.png */, 157 | E4D22BCE1DAE203C00EB8F7E /* test.txt */, 158 | ); 159 | name = Resource; 160 | path = ../../Resource; 161 | sourceTree = ""; 162 | }; 163 | /* End PBXGroup section */ 164 | 165 | /* Begin PBXNativeTarget section */ 166 | E4A331A31DAE0B3D00B59A16 /* SwiftDemo */ = { 167 | isa = PBXNativeTarget; 168 | buildConfigurationList = E4A331B61DAE0B3D00B59A16 /* Build configuration list for PBXNativeTarget "SwiftDemo" */; 169 | buildPhases = ( 170 | 0E44B47670F8F73369558D69 /* [CP] Check Pods Manifest.lock */, 171 | E4A331A01DAE0B3D00B59A16 /* Sources */, 172 | E4A331A11DAE0B3D00B59A16 /* Frameworks */, 173 | E4A331A21DAE0B3D00B59A16 /* Resources */, 174 | ); 175 | buildRules = ( 176 | ); 177 | dependencies = ( 178 | ); 179 | name = SwiftDemo; 180 | productName = SwiftDemo; 181 | productReference = E4A331A41DAE0B3D00B59A16 /* SwiftDemo.app */; 182 | productType = "com.apple.product-type.application"; 183 | }; 184 | /* End PBXNativeTarget section */ 185 | 186 | /* Begin PBXProject section */ 187 | E4A3319C1DAE0B3D00B59A16 /* Project object */ = { 188 | isa = PBXProject; 189 | attributes = { 190 | LastSwiftUpdateCheck = 0800; 191 | LastUpgradeCheck = 0810; 192 | ORGANIZATIONNAME = amao; 193 | TargetAttributes = { 194 | E4A331A31DAE0B3D00B59A16 = { 195 | CreatedOnToolsVersion = 8.0; 196 | DevelopmentTeam = L5CU59RTNH; 197 | LastSwiftMigration = 0800; 198 | ProvisioningStyle = Automatic; 199 | }; 200 | }; 201 | }; 202 | buildConfigurationList = E4A3319F1DAE0B3D00B59A16 /* Build configuration list for PBXProject "SwiftDemo" */; 203 | compatibilityVersion = "Xcode 3.2"; 204 | developmentRegion = English; 205 | hasScannedForEncodings = 0; 206 | knownRegions = ( 207 | English, 208 | en, 209 | Base, 210 | ); 211 | mainGroup = E4A3319B1DAE0B3D00B59A16; 212 | productRefGroup = E4A331A51DAE0B3D00B59A16 /* Products */; 213 | projectDirPath = ""; 214 | projectRoot = ""; 215 | targets = ( 216 | E4A331A31DAE0B3D00B59A16 /* SwiftDemo */, 217 | ); 218 | }; 219 | /* End PBXProject section */ 220 | 221 | /* Begin PBXResourcesBuildPhase section */ 222 | E4A331A21DAE0B3D00B59A16 /* Resources */ = { 223 | isa = PBXResourcesBuildPhase; 224 | buildActionMask = 2147483647; 225 | files = ( 226 | E4D22BCF1DAE203C00EB8F7E /* avatar.png in Resources */, 227 | E4D22BD01DAE203C00EB8F7E /* haha.png in Resources */, 228 | E4D22BD11DAE203C00EB8F7E /* play@2x.png in Resources */, 229 | E4A331B21DAE0B3D00B59A16 /* LaunchScreen.storyboard in Resources */, 230 | E4A331AF1DAE0B3D00B59A16 /* Assets.xcassets in Resources */, 231 | E4D22BD21DAE203C00EB8F7E /* test.txt in Resources */, 232 | E4A331AD1DAE0B3D00B59A16 /* Main.storyboard in Resources */, 233 | ); 234 | runOnlyForDeploymentPostprocessing = 0; 235 | }; 236 | /* End PBXResourcesBuildPhase section */ 237 | 238 | /* Begin PBXShellScriptBuildPhase section */ 239 | 0E44B47670F8F73369558D69 /* [CP] Check Pods Manifest.lock */ = { 240 | isa = PBXShellScriptBuildPhase; 241 | buildActionMask = 2147483647; 242 | files = ( 243 | ); 244 | inputPaths = ( 245 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 246 | "${PODS_ROOT}/Manifest.lock", 247 | ); 248 | name = "[CP] Check Pods Manifest.lock"; 249 | outputPaths = ( 250 | "$(DERIVED_FILE_DIR)/Pods-SwiftDemo-checkManifestLockResult.txt", 251 | ); 252 | runOnlyForDeploymentPostprocessing = 0; 253 | shellPath = /bin/sh; 254 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 255 | showEnvVarsInLog = 0; 256 | }; 257 | /* End PBXShellScriptBuildPhase section */ 258 | 259 | /* Begin PBXSourcesBuildPhase section */ 260 | E4A331A01DAE0B3D00B59A16 /* Sources */ = { 261 | isa = PBXSourcesBuildPhase; 262 | buildActionMask = 2147483647; 263 | files = ( 264 | E4A331AA1DAE0B3D00B59A16 /* ViewController.swift in Sources */, 265 | E4A331A81DAE0B3D00B59A16 /* AppDelegate.swift in Sources */, 266 | E4D22BD41DAE227700EB8F7E /* LinksViewController.swift in Sources */, 267 | E4D22BDC1DAE348500EB8F7E /* LongTextViewController.swift in Sources */, 268 | E40951AE1DAF27E300773E64 /* LineBreakModeViewController.swift in Sources */, 269 | E4D22BC01DAE180100EB8F7E /* CustomTextViewController.swift in Sources */, 270 | E4A331E61DAE14CB00B59A16 /* BaseViewController.swift in Sources */, 271 | E4D22BC91DAE191C00EB8F7E /* Util.swift in Sources */, 272 | E4D22BD81DAE315300EB8F7E /* ImagesViewController.swift in Sources */, 273 | E40951B01DAF2ACC00773E64 /* TextAlignmentViewController.swift in Sources */, 274 | E4D22BDA1DAE325500EB8F7E /* AttachmentViewController.swift in Sources */, 275 | E4A331E21DAE0FDD00B59A16 /* DemoTableViewController.swift in Sources */, 276 | E4D22BBE1DAE166C00EB8F7E /* BasicAttributedLabelViewController.swift in Sources */, 277 | ); 278 | runOnlyForDeploymentPostprocessing = 0; 279 | }; 280 | /* End PBXSourcesBuildPhase section */ 281 | 282 | /* Begin PBXVariantGroup section */ 283 | E4A331AB1DAE0B3D00B59A16 /* Main.storyboard */ = { 284 | isa = PBXVariantGroup; 285 | children = ( 286 | E4A331AC1DAE0B3D00B59A16 /* Base */, 287 | ); 288 | name = Main.storyboard; 289 | sourceTree = ""; 290 | }; 291 | E4A331B01DAE0B3D00B59A16 /* LaunchScreen.storyboard */ = { 292 | isa = PBXVariantGroup; 293 | children = ( 294 | E4A331B11DAE0B3D00B59A16 /* Base */, 295 | ); 296 | name = LaunchScreen.storyboard; 297 | sourceTree = ""; 298 | }; 299 | /* End PBXVariantGroup section */ 300 | 301 | /* Begin XCBuildConfiguration section */ 302 | E4A331B41DAE0B3D00B59A16 /* Debug */ = { 303 | isa = XCBuildConfiguration; 304 | buildSettings = { 305 | ALWAYS_SEARCH_USER_PATHS = NO; 306 | CLANG_ANALYZER_NONNULL = YES; 307 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 308 | CLANG_CXX_LIBRARY = "libc++"; 309 | CLANG_ENABLE_MODULES = YES; 310 | CLANG_ENABLE_OBJC_ARC = YES; 311 | CLANG_WARN_BOOL_CONVERSION = YES; 312 | CLANG_WARN_CONSTANT_CONVERSION = YES; 313 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 314 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 315 | CLANG_WARN_EMPTY_BODY = YES; 316 | CLANG_WARN_ENUM_CONVERSION = YES; 317 | CLANG_WARN_INFINITE_RECURSION = YES; 318 | CLANG_WARN_INT_CONVERSION = YES; 319 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 320 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 321 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 322 | CLANG_WARN_UNREACHABLE_CODE = YES; 323 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 324 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 325 | COPY_PHASE_STRIP = NO; 326 | DEBUG_INFORMATION_FORMAT = dwarf; 327 | ENABLE_STRICT_OBJC_MSGSEND = YES; 328 | ENABLE_TESTABILITY = YES; 329 | GCC_C_LANGUAGE_STANDARD = gnu99; 330 | GCC_DYNAMIC_NO_PIC = NO; 331 | GCC_NO_COMMON_BLOCKS = YES; 332 | GCC_OPTIMIZATION_LEVEL = 0; 333 | GCC_PREPROCESSOR_DEFINITIONS = ( 334 | "DEBUG=1", 335 | "$(inherited)", 336 | ); 337 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 338 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 339 | GCC_WARN_UNDECLARED_SELECTOR = YES; 340 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 341 | GCC_WARN_UNUSED_FUNCTION = YES; 342 | GCC_WARN_UNUSED_VARIABLE = YES; 343 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 344 | MTL_ENABLE_DEBUG_INFO = YES; 345 | ONLY_ACTIVE_ARCH = YES; 346 | SDKROOT = iphoneos; 347 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 348 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 349 | }; 350 | name = Debug; 351 | }; 352 | E4A331B51DAE0B3D00B59A16 /* Release */ = { 353 | isa = XCBuildConfiguration; 354 | buildSettings = { 355 | ALWAYS_SEARCH_USER_PATHS = NO; 356 | CLANG_ANALYZER_NONNULL = YES; 357 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 358 | CLANG_CXX_LIBRARY = "libc++"; 359 | CLANG_ENABLE_MODULES = YES; 360 | CLANG_ENABLE_OBJC_ARC = YES; 361 | CLANG_WARN_BOOL_CONVERSION = YES; 362 | CLANG_WARN_CONSTANT_CONVERSION = YES; 363 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 364 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 365 | CLANG_WARN_EMPTY_BODY = YES; 366 | CLANG_WARN_ENUM_CONVERSION = YES; 367 | CLANG_WARN_INFINITE_RECURSION = YES; 368 | CLANG_WARN_INT_CONVERSION = YES; 369 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 370 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 371 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 372 | CLANG_WARN_UNREACHABLE_CODE = YES; 373 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 374 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 375 | COPY_PHASE_STRIP = NO; 376 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 377 | ENABLE_NS_ASSERTIONS = NO; 378 | ENABLE_STRICT_OBJC_MSGSEND = YES; 379 | GCC_C_LANGUAGE_STANDARD = gnu99; 380 | GCC_NO_COMMON_BLOCKS = YES; 381 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 382 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 383 | GCC_WARN_UNDECLARED_SELECTOR = YES; 384 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 385 | GCC_WARN_UNUSED_FUNCTION = YES; 386 | GCC_WARN_UNUSED_VARIABLE = YES; 387 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 388 | MTL_ENABLE_DEBUG_INFO = NO; 389 | SDKROOT = iphoneos; 390 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 391 | VALIDATE_PRODUCT = YES; 392 | }; 393 | name = Release; 394 | }; 395 | E4A331B71DAE0B3D00B59A16 /* Debug */ = { 396 | isa = XCBuildConfiguration; 397 | baseConfigurationReference = C43C45C0E63F53F1B14DF04D /* Pods-SwiftDemo.debug.xcconfig */; 398 | buildSettings = { 399 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 400 | CLANG_ENABLE_MODULES = YES; 401 | DEVELOPMENT_TEAM = L5CU59RTNH; 402 | INFOPLIST_FILE = SwiftDemo/Info.plist; 403 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 404 | PRODUCT_BUNDLE_IDENTIFIER = com.xiangwangfeng.www.SwiftDemo; 405 | PRODUCT_NAME = "$(TARGET_NAME)"; 406 | SWIFT_OBJC_BRIDGING_HEADER = "Classes/SwiftDemo-Bridging-Header.h"; 407 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 408 | SWIFT_VERSION = 5.0; 409 | }; 410 | name = Debug; 411 | }; 412 | E4A331B81DAE0B3D00B59A16 /* Release */ = { 413 | isa = XCBuildConfiguration; 414 | baseConfigurationReference = 4BCEAB4CF3E5C6DDE3B882EA /* Pods-SwiftDemo.release.xcconfig */; 415 | buildSettings = { 416 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 417 | CLANG_ENABLE_MODULES = YES; 418 | DEVELOPMENT_TEAM = L5CU59RTNH; 419 | INFOPLIST_FILE = SwiftDemo/Info.plist; 420 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 421 | PRODUCT_BUNDLE_IDENTIFIER = com.xiangwangfeng.www.SwiftDemo; 422 | PRODUCT_NAME = "$(TARGET_NAME)"; 423 | SWIFT_OBJC_BRIDGING_HEADER = "Classes/SwiftDemo-Bridging-Header.h"; 424 | SWIFT_VERSION = 5.0; 425 | }; 426 | name = Release; 427 | }; 428 | /* End XCBuildConfiguration section */ 429 | 430 | /* Begin XCConfigurationList section */ 431 | E4A3319F1DAE0B3D00B59A16 /* Build configuration list for PBXProject "SwiftDemo" */ = { 432 | isa = XCConfigurationList; 433 | buildConfigurations = ( 434 | E4A331B41DAE0B3D00B59A16 /* Debug */, 435 | E4A331B51DAE0B3D00B59A16 /* Release */, 436 | ); 437 | defaultConfigurationIsVisible = 0; 438 | defaultConfigurationName = Release; 439 | }; 440 | E4A331B61DAE0B3D00B59A16 /* Build configuration list for PBXNativeTarget "SwiftDemo" */ = { 441 | isa = XCConfigurationList; 442 | buildConfigurations = ( 443 | E4A331B71DAE0B3D00B59A16 /* Debug */, 444 | E4A331B81DAE0B3D00B59A16 /* Release */, 445 | ); 446 | defaultConfigurationIsVisible = 0; 447 | defaultConfigurationName = Release; 448 | }; 449 | /* End XCConfigurationList section */ 450 | }; 451 | rootObject = E4A3319C1DAE0B3D00B59A16 /* Project object */; 452 | } 453 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // SwiftDemo 4 | // 5 | // Created by amao on 2016/10/12. 6 | // Copyright © 2016年 amao. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 18 | 19 | self.window = UIWindow(frame: UIScreen.main.bounds) 20 | let vc = DemoTableViewController() 21 | let nav = UINavigationController(rootViewController: vc) 22 | self.window?.rootViewController = nav 23 | self.window?.makeKeyAndVisible() 24 | return true 25 | } 26 | 27 | func applicationWillResignActive(_ application: UIApplication) { 28 | } 29 | 30 | func applicationDidEnterBackground(_ application: UIApplication) { 31 | } 32 | 33 | func applicationWillEnterForeground(_ application: UIApplication) { 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | } 38 | 39 | func applicationWillTerminate(_ application: UIApplication) { 40 | 41 | } 42 | 43 | 44 | } 45 | 46 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Assets.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" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIRequiredDeviceCapabilities 26 | 27 | armv7 28 | 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /SwiftDemo/SwiftDemo/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // SwiftDemo 4 | // 5 | // Created by amao on 2016/10/12. 6 | // Copyright © 2016年 amao. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | 12 | class ViewController: UIViewController { 13 | 14 | override func viewDidLoad() { 15 | super.viewDidLoad() 16 | 17 | } 18 | 19 | override func didReceiveMemoryWarning() { 20 | super.didReceiveMemoryWarning() 21 | } 22 | 23 | 24 | } 25 | 26 | -------------------------------------------------------------------------------- /pod_push.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import re 4 | 5 | pod_spec_filename = 'M80AttributedLabel.podspec' 6 | 7 | def run(): 8 | new_version = get_new_version() 9 | old_version = get_old_version() 10 | print('current version is [' + old_version + ']') 11 | if new_version is not None and old_version is not None: 12 | question = 'do u want to upgrade current pod to \'' + new_version + '\' ? (y/n)\n' 13 | choice = input(question).lower() 14 | if choice == 'y' or choice == 'yes': 15 | update(old_version,new_version) 16 | 17 | def update(old_version,new_version): 18 | 19 | if run_shell('pod lib lint --no-clean') != 0: 20 | return 21 | 22 | if update_pod_spec(old_version,new_version) == False: 23 | return 24 | 25 | git_add = 'git add .' 26 | git_commit = 'git commit . -m " pod version update to ' + new_version + '"' 27 | git_push = 'git push' 28 | git_add_tag = 'git tag ' + new_version 29 | git_push_tag = 'git push --tags' 30 | pod_push = 'pod trunk push ' + pod_spec_filename 31 | 32 | command_list = [git_add,git_commit,git_push,git_add_tag,git_push_tag,pod_push] 33 | for command in command_list: 34 | run_shell(command) 35 | 36 | 37 | 38 | 39 | def get_old_version(): 40 | old_version = None 41 | version_pattern = r"\s*s.version\s+=\s+'(\d+.\d+.\d+)'" 42 | pod_file = './' + pod_spec_filename 43 | with open(pod_file) as podspec: 44 | content = podspec.read() 45 | old_version = re.search(version_pattern,content).group(1) 46 | return old_version 47 | 48 | 49 | def update_pod_spec(old_version,new_version): 50 | pod_file = './' + pod_spec_filename 51 | new_content = None 52 | with open(pod_file) as podspec: 53 | content = podspec.read() 54 | new_content = content.replace(old_version,new_version,1) 55 | if new_content is not None: 56 | with open(pod_file,'w') as podspec: 57 | podspec.write(new_content) 58 | return True 59 | return False 60 | 61 | 62 | 63 | def run_shell(command): 64 | return os.system(command) 65 | 66 | 67 | def get_new_version(): 68 | version = None 69 | if len(sys.argv) == 2: 70 | candidate_version = sys.argv[1].strip() 71 | if is_valid_version(candidate_version): 72 | version = candidate_version 73 | else: 74 | print('version needed') 75 | return version 76 | 77 | def is_valid_version(version): 78 | valid = False 79 | components = version.split('.') 80 | if len(components) >= 3: 81 | for component in components: 82 | try: 83 | num = int(component) 84 | except: 85 | print('invalid version: ',version) 86 | return False 87 | valid = True 88 | if valid is False: 89 | print('invalid version: ',version) 90 | return valid 91 | 92 | if __name__ == '__main__': 93 | run() --------------------------------------------------------------------------------