├── .gitignore ├── HTCopyableLabel.h ├── HTCopyableLabel.m ├── HTCopyableLabel.podspec ├── HTCopyableLabelDemo.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── HTCopyableLabelDemo.xccheckout └── xcuserdata │ └── jonsibley.xcuserdatad │ ├── xcdebugger │ ├── Breakpoints.xcbkptlist │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── HTCopyableLabelDemo.xcscheme │ └── xcschememanagement.plist ├── HTCopyableLabelDemo ├── Default-568h@2x.png ├── Default.png ├── Default@2x.png ├── HTAppDelegate.h ├── HTAppDelegate.m ├── HTCopyableLabelDemo-Info.plist ├── HTCopyableLabelDemo-Prefix.pch ├── HTPasteViewController.h ├── HTPasteViewController.m ├── HTViewController.h ├── HTViewController.m ├── en.lproj │ ├── InfoPlist.strings │ └── MainStoryboard.storyboard └── main.m ├── LICENSE.txt ├── README.md ├── demo.gif └── ht-logo-black.png /.gitignore: -------------------------------------------------------------------------------- 1 | .svn 2 | .idea/* 3 | !.idea/codeStyleSettings.xml 4 | *.pyc 5 | .project 6 | .classpath 7 | *.mode1v3 8 | *.pbxuser 9 | *.DS_Store 10 | *~ 11 | *.swp 12 | xcuserdata 13 | Pods/Pods-Acknowledgements.markdown 14 | Pods/Pods-Acknowledgements.plist 15 | *.orig 16 | *.pbxproj.bak 17 | build 18 | -------------------------------------------------------------------------------- /HTCopyableLabel.h: -------------------------------------------------------------------------------- 1 | // 2 | // HTCopyableLabel.h 3 | // HotelTonight 4 | // 5 | // Created by Jonathan Sibley on 2/6/13. 6 | // Copyright (c) 2013 Hotel Tonight. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class HTCopyableLabel; 12 | 13 | @protocol HTCopyableLabelDelegate 14 | 15 | @optional 16 | - (NSString *)stringToCopyForCopyableLabel:(HTCopyableLabel *)copyableLabel; 17 | - (CGRect)copyMenuTargetRectInCopyableLabelCoordinates:(HTCopyableLabel *)copyableLabel; 18 | 19 | @end 20 | 21 | @interface HTCopyableLabel : UILabel 22 | 23 | @property (nonatomic, assign) BOOL copyingEnabled; // Defaults to YES 24 | 25 | @property (nonatomic, weak) id copyableLabelDelegate; 26 | 27 | @property (nonatomic, assign) UIMenuControllerArrowDirection copyMenuArrowDirection; // Defaults to UIMenuControllerArrowDefault 28 | 29 | // You may want to add longPressGestureRecognizer to a container view 30 | @property (nonatomic, strong, readonly) UILongPressGestureRecognizer *longPressGestureRecognizer; 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /HTCopyableLabel.m: -------------------------------------------------------------------------------- 1 | // 2 | // HTCopyableLabel.m 3 | // HotelTonight 4 | // 5 | // Created by Jonathan Sibley on 2/6/13. 6 | // Copyright (c) 2013 Hotel Tonight. All rights reserved. 7 | // 8 | 9 | #import "HTCopyableLabel.h" 10 | 11 | @interface HTCopyableLabel () 12 | 13 | @end 14 | 15 | @implementation HTCopyableLabel 16 | 17 | - (id)initWithFrame:(CGRect)frame 18 | { 19 | if (self = [super initWithFrame:frame]) 20 | { 21 | [self setup]; 22 | } 23 | return self; 24 | } 25 | 26 | - (void)awakeFromNib 27 | { 28 | [self setup]; 29 | } 30 | 31 | - (void)setup 32 | { 33 | _longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressGestureRecognized:)]; 34 | [self addGestureRecognizer:_longPressGestureRecognizer]; 35 | 36 | _copyMenuArrowDirection = UIMenuControllerArrowDefault; 37 | 38 | _copyingEnabled = YES; 39 | self.userInteractionEnabled = YES; 40 | } 41 | 42 | #pragma mark - Public 43 | 44 | - (void)setCopyingEnabled:(BOOL)copyingEnabled 45 | { 46 | if (_copyingEnabled != copyingEnabled) 47 | { 48 | [self willChangeValueForKey:@"copyingEnabled"]; 49 | _copyingEnabled = copyingEnabled; 50 | [self didChangeValueForKey:@"copyingEnabled"]; 51 | 52 | self.userInteractionEnabled = copyingEnabled; 53 | self.longPressGestureRecognizer.enabled = copyingEnabled; 54 | } 55 | } 56 | 57 | #pragma mark - Callbacks 58 | 59 | - (void)longPressGestureRecognized:(UILongPressGestureRecognizer *)gestureRecognizer 60 | { 61 | if (gestureRecognizer == self.longPressGestureRecognizer) 62 | { 63 | if (gestureRecognizer.state == UIGestureRecognizerStateBegan) 64 | { 65 | // NSAssert([self becomeFirstResponder], @"Sorry, UIMenuController will not work with %@ since it cannot become first responder", self); 66 | [self becomeFirstResponder]; // must be called even when NS_BLOCK_ASSERTIONS=0 67 | 68 | UIMenuController *copyMenu = [UIMenuController sharedMenuController]; 69 | if ([self.copyableLabelDelegate respondsToSelector:@selector(copyMenuTargetRectInCopyableLabelCoordinates:)]) 70 | { 71 | [copyMenu setTargetRect:[self.copyableLabelDelegate copyMenuTargetRectInCopyableLabelCoordinates:self] inView:self]; 72 | } 73 | else 74 | { 75 | [copyMenu setTargetRect:self.bounds inView:self]; 76 | } 77 | copyMenu.arrowDirection = self.copyMenuArrowDirection; 78 | [copyMenu setMenuVisible:YES animated:YES]; 79 | } 80 | } 81 | } 82 | 83 | #pragma mark - UIResponder 84 | 85 | - (BOOL)canBecomeFirstResponder 86 | { 87 | return self.copyingEnabled; 88 | } 89 | 90 | - (BOOL)canPerformAction:(SEL)action withSender:(id)sender 91 | { 92 | BOOL retValue = NO; 93 | 94 | if (action == @selector(copy:)) 95 | { 96 | if (self.copyingEnabled) 97 | { 98 | retValue = YES; 99 | } 100 | } 101 | else 102 | { 103 | // Pass the canPerformAction:withSender: message to the superclass 104 | // and possibly up the responder chain. 105 | retValue = [super canPerformAction:action withSender:sender]; 106 | } 107 | 108 | return retValue; 109 | } 110 | 111 | - (void)copy:(id)sender 112 | { 113 | if (self.copyingEnabled) 114 | { 115 | UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; 116 | NSString *stringToCopy; 117 | if ([self.copyableLabelDelegate respondsToSelector:@selector(stringToCopyForCopyableLabel:)]) 118 | { 119 | stringToCopy = [self.copyableLabelDelegate stringToCopyForCopyableLabel:self]; 120 | } 121 | else 122 | { 123 | stringToCopy = self.text; 124 | } 125 | 126 | [pasteboard setString:stringToCopy]; 127 | } 128 | } 129 | 130 | @end 131 | -------------------------------------------------------------------------------- /HTCopyableLabel.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "HTCopyableLabel" 3 | s.version = "0.0.7" 4 | s.summary = "HTCopyableLabel is a subclass of UILabel that makes it easy to allow users to copy a label's text." 5 | s.homepage = "https://github.com/hoteltonight/HTCopyableLabel" 6 | s.screenshots = "https://raw.github.com/hoteltonight/HTCopyableLabel/master/demo.gif" 7 | s.license = { :type => 'MIT', :file => 'LICENSE.txt' } 8 | s.author = { "Jonathan Sibley" => "jonsibley@gmail.com" } 9 | s.source = { :git => "https://github.com/hoteltonight/HTCopyableLabel.git", :tag => "0.0.7" } 10 | s.source_files = 'HTCopyableLabel.{h,m}' 11 | s.platform = :ios 12 | s.ios.deployment_target = '5.0' 13 | s.requires_arc = true 14 | end 15 | -------------------------------------------------------------------------------- /HTCopyableLabelDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 48759F5F17D47017001FC123 /* HTCopyableLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = 48759F5E17D47017001FC123 /* HTCopyableLabel.m */; }; 11 | 8D20BF0E179FEC7E0093BA0D /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8D20BF0D179FEC7E0093BA0D /* UIKit.framework */; }; 12 | 8D20BF10179FEC7E0093BA0D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8D20BF0F179FEC7E0093BA0D /* Foundation.framework */; }; 13 | 8D20BF12179FEC7E0093BA0D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8D20BF11179FEC7E0093BA0D /* CoreGraphics.framework */; }; 14 | 8D20BF18179FEC7E0093BA0D /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8D20BF16179FEC7E0093BA0D /* InfoPlist.strings */; }; 15 | 8D20BF1A179FEC7E0093BA0D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D20BF19179FEC7E0093BA0D /* main.m */; }; 16 | 8D20BF1E179FEC7E0093BA0D /* HTAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D20BF1D179FEC7E0093BA0D /* HTAppDelegate.m */; }; 17 | 8D20BF20179FEC7E0093BA0D /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = 8D20BF1F179FEC7E0093BA0D /* Default.png */; }; 18 | 8D20BF22179FEC7E0093BA0D /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8D20BF21179FEC7E0093BA0D /* Default@2x.png */; }; 19 | 8D20BF24179FEC7E0093BA0D /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8D20BF23179FEC7E0093BA0D /* Default-568h@2x.png */; }; 20 | 8D20BF27179FEC7E0093BA0D /* MainStoryboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8D20BF25179FEC7E0093BA0D /* MainStoryboard.storyboard */; }; 21 | 8D20BF2A179FEC7E0093BA0D /* HTViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D20BF29179FEC7E0093BA0D /* HTViewController.m */; }; 22 | 8D85CB6E17A00065008C14D1 /* HTPasteViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D85CB6D17A00065008C14D1 /* HTPasteViewController.m */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXFileReference section */ 26 | 48759F5D17D47017001FC123 /* HTCopyableLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTCopyableLabel.h; sourceTree = ""; }; 27 | 48759F5E17D47017001FC123 /* HTCopyableLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTCopyableLabel.m; sourceTree = ""; }; 28 | 8D20BF0A179FEC7E0093BA0D /* HTCopyableLabelDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HTCopyableLabelDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 29 | 8D20BF0D179FEC7E0093BA0D /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 30 | 8D20BF0F179FEC7E0093BA0D /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 31 | 8D20BF11179FEC7E0093BA0D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 32 | 8D20BF15179FEC7E0093BA0D /* HTCopyableLabelDemo-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "HTCopyableLabelDemo-Info.plist"; sourceTree = ""; }; 33 | 8D20BF17179FEC7E0093BA0D /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 34 | 8D20BF19179FEC7E0093BA0D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 35 | 8D20BF1B179FEC7E0093BA0D /* HTCopyableLabelDemo-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "HTCopyableLabelDemo-Prefix.pch"; sourceTree = ""; }; 36 | 8D20BF1C179FEC7E0093BA0D /* HTAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTAppDelegate.h; sourceTree = ""; }; 37 | 8D20BF1D179FEC7E0093BA0D /* HTAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HTAppDelegate.m; sourceTree = ""; }; 38 | 8D20BF1F179FEC7E0093BA0D /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = ""; }; 39 | 8D20BF21179FEC7E0093BA0D /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = ""; }; 40 | 8D20BF23179FEC7E0093BA0D /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; 41 | 8D20BF26179FEC7E0093BA0D /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/MainStoryboard.storyboard; sourceTree = ""; }; 42 | 8D20BF28179FEC7E0093BA0D /* HTViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTViewController.h; sourceTree = ""; }; 43 | 8D20BF29179FEC7E0093BA0D /* HTViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HTViewController.m; sourceTree = ""; }; 44 | 8D85CB6C17A00065008C14D1 /* HTPasteViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTPasteViewController.h; sourceTree = ""; }; 45 | 8D85CB6D17A00065008C14D1 /* HTPasteViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTPasteViewController.m; sourceTree = ""; }; 46 | /* End PBXFileReference section */ 47 | 48 | /* Begin PBXFrameworksBuildPhase section */ 49 | 8D20BF07179FEC7E0093BA0D /* Frameworks */ = { 50 | isa = PBXFrameworksBuildPhase; 51 | buildActionMask = 2147483647; 52 | files = ( 53 | 8D20BF0E179FEC7E0093BA0D /* UIKit.framework in Frameworks */, 54 | 8D20BF10179FEC7E0093BA0D /* Foundation.framework in Frameworks */, 55 | 8D20BF12179FEC7E0093BA0D /* CoreGraphics.framework in Frameworks */, 56 | ); 57 | runOnlyForDeploymentPostprocessing = 0; 58 | }; 59 | /* End PBXFrameworksBuildPhase section */ 60 | 61 | /* Begin PBXGroup section */ 62 | 48759F6017D4701B001FC123 /* HTCopyableLabel */ = { 63 | isa = PBXGroup; 64 | children = ( 65 | 48759F5D17D47017001FC123 /* HTCopyableLabel.h */, 66 | 48759F5E17D47017001FC123 /* HTCopyableLabel.m */, 67 | ); 68 | name = HTCopyableLabel; 69 | sourceTree = ""; 70 | }; 71 | 8D20BF01179FEC7E0093BA0D = { 72 | isa = PBXGroup; 73 | children = ( 74 | 48759F6017D4701B001FC123 /* HTCopyableLabel */, 75 | 8D20BF13179FEC7E0093BA0D /* HTCopyableLabelDemo */, 76 | 8D20BF0C179FEC7E0093BA0D /* Frameworks */, 77 | 8D20BF0B179FEC7E0093BA0D /* Products */, 78 | ); 79 | sourceTree = ""; 80 | }; 81 | 8D20BF0B179FEC7E0093BA0D /* Products */ = { 82 | isa = PBXGroup; 83 | children = ( 84 | 8D20BF0A179FEC7E0093BA0D /* HTCopyableLabelDemo.app */, 85 | ); 86 | name = Products; 87 | sourceTree = ""; 88 | }; 89 | 8D20BF0C179FEC7E0093BA0D /* Frameworks */ = { 90 | isa = PBXGroup; 91 | children = ( 92 | 8D20BF0D179FEC7E0093BA0D /* UIKit.framework */, 93 | 8D20BF0F179FEC7E0093BA0D /* Foundation.framework */, 94 | 8D20BF11179FEC7E0093BA0D /* CoreGraphics.framework */, 95 | ); 96 | name = Frameworks; 97 | sourceTree = ""; 98 | }; 99 | 8D20BF13179FEC7E0093BA0D /* HTCopyableLabelDemo */ = { 100 | isa = PBXGroup; 101 | children = ( 102 | 8D20BF34179FECDC0093BA0D /* Demo */, 103 | 8D20BF14179FEC7E0093BA0D /* Supporting Files */, 104 | ); 105 | path = HTCopyableLabelDemo; 106 | sourceTree = ""; 107 | }; 108 | 8D20BF14179FEC7E0093BA0D /* Supporting Files */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | 8D20BF15179FEC7E0093BA0D /* HTCopyableLabelDemo-Info.plist */, 112 | 8D20BF16179FEC7E0093BA0D /* InfoPlist.strings */, 113 | 8D20BF19179FEC7E0093BA0D /* main.m */, 114 | 8D20BF1B179FEC7E0093BA0D /* HTCopyableLabelDemo-Prefix.pch */, 115 | 8D20BF1F179FEC7E0093BA0D /* Default.png */, 116 | 8D20BF21179FEC7E0093BA0D /* Default@2x.png */, 117 | 8D20BF23179FEC7E0093BA0D /* Default-568h@2x.png */, 118 | ); 119 | name = "Supporting Files"; 120 | sourceTree = ""; 121 | }; 122 | 8D20BF34179FECDC0093BA0D /* Demo */ = { 123 | isa = PBXGroup; 124 | children = ( 125 | 8D20BF1C179FEC7E0093BA0D /* HTAppDelegate.h */, 126 | 8D20BF1D179FEC7E0093BA0D /* HTAppDelegate.m */, 127 | 8D20BF25179FEC7E0093BA0D /* MainStoryboard.storyboard */, 128 | 8D20BF28179FEC7E0093BA0D /* HTViewController.h */, 129 | 8D20BF29179FEC7E0093BA0D /* HTViewController.m */, 130 | 8D85CB6C17A00065008C14D1 /* HTPasteViewController.h */, 131 | 8D85CB6D17A00065008C14D1 /* HTPasteViewController.m */, 132 | ); 133 | name = Demo; 134 | sourceTree = ""; 135 | }; 136 | /* End PBXGroup section */ 137 | 138 | /* Begin PBXNativeTarget section */ 139 | 8D20BF09179FEC7E0093BA0D /* HTCopyableLabelDemo */ = { 140 | isa = PBXNativeTarget; 141 | buildConfigurationList = 8D20BF2D179FEC7E0093BA0D /* Build configuration list for PBXNativeTarget "HTCopyableLabelDemo" */; 142 | buildPhases = ( 143 | 8D20BF06179FEC7E0093BA0D /* Sources */, 144 | 8D20BF07179FEC7E0093BA0D /* Frameworks */, 145 | 8D20BF08179FEC7E0093BA0D /* Resources */, 146 | ); 147 | buildRules = ( 148 | ); 149 | dependencies = ( 150 | ); 151 | name = HTCopyableLabelDemo; 152 | productName = HTCopyableLabelDemo; 153 | productReference = 8D20BF0A179FEC7E0093BA0D /* HTCopyableLabelDemo.app */; 154 | productType = "com.apple.product-type.application"; 155 | }; 156 | /* End PBXNativeTarget section */ 157 | 158 | /* Begin PBXProject section */ 159 | 8D20BF02179FEC7E0093BA0D /* Project object */ = { 160 | isa = PBXProject; 161 | attributes = { 162 | CLASSPREFIX = HT; 163 | LastUpgradeCheck = 0460; 164 | ORGANIZATIONNAME = HotelTonight; 165 | }; 166 | buildConfigurationList = 8D20BF05179FEC7E0093BA0D /* Build configuration list for PBXProject "HTCopyableLabelDemo" */; 167 | compatibilityVersion = "Xcode 3.2"; 168 | developmentRegion = English; 169 | hasScannedForEncodings = 0; 170 | knownRegions = ( 171 | en, 172 | ); 173 | mainGroup = 8D20BF01179FEC7E0093BA0D; 174 | productRefGroup = 8D20BF0B179FEC7E0093BA0D /* Products */; 175 | projectDirPath = ""; 176 | projectRoot = ""; 177 | targets = ( 178 | 8D20BF09179FEC7E0093BA0D /* HTCopyableLabelDemo */, 179 | ); 180 | }; 181 | /* End PBXProject section */ 182 | 183 | /* Begin PBXResourcesBuildPhase section */ 184 | 8D20BF08179FEC7E0093BA0D /* Resources */ = { 185 | isa = PBXResourcesBuildPhase; 186 | buildActionMask = 2147483647; 187 | files = ( 188 | 8D20BF18179FEC7E0093BA0D /* InfoPlist.strings in Resources */, 189 | 8D20BF20179FEC7E0093BA0D /* Default.png in Resources */, 190 | 8D20BF22179FEC7E0093BA0D /* Default@2x.png in Resources */, 191 | 8D20BF24179FEC7E0093BA0D /* Default-568h@2x.png in Resources */, 192 | 8D20BF27179FEC7E0093BA0D /* MainStoryboard.storyboard in Resources */, 193 | ); 194 | runOnlyForDeploymentPostprocessing = 0; 195 | }; 196 | /* End PBXResourcesBuildPhase section */ 197 | 198 | /* Begin PBXSourcesBuildPhase section */ 199 | 8D20BF06179FEC7E0093BA0D /* Sources */ = { 200 | isa = PBXSourcesBuildPhase; 201 | buildActionMask = 2147483647; 202 | files = ( 203 | 8D20BF1A179FEC7E0093BA0D /* main.m in Sources */, 204 | 8D20BF1E179FEC7E0093BA0D /* HTAppDelegate.m in Sources */, 205 | 8D20BF2A179FEC7E0093BA0D /* HTViewController.m in Sources */, 206 | 8D85CB6E17A00065008C14D1 /* HTPasteViewController.m in Sources */, 207 | 48759F5F17D47017001FC123 /* HTCopyableLabel.m in Sources */, 208 | ); 209 | runOnlyForDeploymentPostprocessing = 0; 210 | }; 211 | /* End PBXSourcesBuildPhase section */ 212 | 213 | /* Begin PBXVariantGroup section */ 214 | 8D20BF16179FEC7E0093BA0D /* InfoPlist.strings */ = { 215 | isa = PBXVariantGroup; 216 | children = ( 217 | 8D20BF17179FEC7E0093BA0D /* en */, 218 | ); 219 | name = InfoPlist.strings; 220 | sourceTree = ""; 221 | }; 222 | 8D20BF25179FEC7E0093BA0D /* MainStoryboard.storyboard */ = { 223 | isa = PBXVariantGroup; 224 | children = ( 225 | 8D20BF26179FEC7E0093BA0D /* en */, 226 | ); 227 | name = MainStoryboard.storyboard; 228 | sourceTree = ""; 229 | }; 230 | /* End PBXVariantGroup section */ 231 | 232 | /* Begin XCBuildConfiguration section */ 233 | 8D20BF2B179FEC7E0093BA0D /* Debug */ = { 234 | isa = XCBuildConfiguration; 235 | buildSettings = { 236 | ALWAYS_SEARCH_USER_PATHS = NO; 237 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 238 | CLANG_CXX_LIBRARY = "libc++"; 239 | CLANG_ENABLE_OBJC_ARC = YES; 240 | CLANG_WARN_CONSTANT_CONVERSION = YES; 241 | CLANG_WARN_EMPTY_BODY = YES; 242 | CLANG_WARN_ENUM_CONVERSION = YES; 243 | CLANG_WARN_INT_CONVERSION = YES; 244 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 245 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 246 | COPY_PHASE_STRIP = NO; 247 | GCC_C_LANGUAGE_STANDARD = gnu99; 248 | GCC_DYNAMIC_NO_PIC = NO; 249 | GCC_OPTIMIZATION_LEVEL = 0; 250 | GCC_PREPROCESSOR_DEFINITIONS = ( 251 | "DEBUG=1", 252 | "$(inherited)", 253 | ); 254 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 255 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 256 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 257 | GCC_WARN_UNUSED_VARIABLE = YES; 258 | IPHONEOS_DEPLOYMENT_TARGET = 6.1; 259 | ONLY_ACTIVE_ARCH = YES; 260 | SDKROOT = iphoneos; 261 | }; 262 | name = Debug; 263 | }; 264 | 8D20BF2C179FEC7E0093BA0D /* Release */ = { 265 | isa = XCBuildConfiguration; 266 | buildSettings = { 267 | ALWAYS_SEARCH_USER_PATHS = NO; 268 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 269 | CLANG_CXX_LIBRARY = "libc++"; 270 | CLANG_ENABLE_OBJC_ARC = YES; 271 | CLANG_WARN_CONSTANT_CONVERSION = YES; 272 | CLANG_WARN_EMPTY_BODY = YES; 273 | CLANG_WARN_ENUM_CONVERSION = YES; 274 | CLANG_WARN_INT_CONVERSION = YES; 275 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 276 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 277 | COPY_PHASE_STRIP = YES; 278 | GCC_C_LANGUAGE_STANDARD = gnu99; 279 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 280 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 281 | GCC_WARN_UNUSED_VARIABLE = YES; 282 | IPHONEOS_DEPLOYMENT_TARGET = 6.1; 283 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 284 | SDKROOT = iphoneos; 285 | VALIDATE_PRODUCT = YES; 286 | }; 287 | name = Release; 288 | }; 289 | 8D20BF2E179FEC7E0093BA0D /* Debug */ = { 290 | isa = XCBuildConfiguration; 291 | buildSettings = { 292 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 293 | GCC_PREFIX_HEADER = "HTCopyableLabelDemo/HTCopyableLabelDemo-Prefix.pch"; 294 | INFOPLIST_FILE = "HTCopyableLabelDemo/HTCopyableLabelDemo-Info.plist"; 295 | PRODUCT_NAME = "$(TARGET_NAME)"; 296 | WRAPPER_EXTENSION = app; 297 | }; 298 | name = Debug; 299 | }; 300 | 8D20BF2F179FEC7E0093BA0D /* Release */ = { 301 | isa = XCBuildConfiguration; 302 | buildSettings = { 303 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 304 | GCC_PREFIX_HEADER = "HTCopyableLabelDemo/HTCopyableLabelDemo-Prefix.pch"; 305 | INFOPLIST_FILE = "HTCopyableLabelDemo/HTCopyableLabelDemo-Info.plist"; 306 | PRODUCT_NAME = "$(TARGET_NAME)"; 307 | WRAPPER_EXTENSION = app; 308 | }; 309 | name = Release; 310 | }; 311 | /* End XCBuildConfiguration section */ 312 | 313 | /* Begin XCConfigurationList section */ 314 | 8D20BF05179FEC7E0093BA0D /* Build configuration list for PBXProject "HTCopyableLabelDemo" */ = { 315 | isa = XCConfigurationList; 316 | buildConfigurations = ( 317 | 8D20BF2B179FEC7E0093BA0D /* Debug */, 318 | 8D20BF2C179FEC7E0093BA0D /* Release */, 319 | ); 320 | defaultConfigurationIsVisible = 0; 321 | defaultConfigurationName = Release; 322 | }; 323 | 8D20BF2D179FEC7E0093BA0D /* Build configuration list for PBXNativeTarget "HTCopyableLabelDemo" */ = { 324 | isa = XCConfigurationList; 325 | buildConfigurations = ( 326 | 8D20BF2E179FEC7E0093BA0D /* Debug */, 327 | 8D20BF2F179FEC7E0093BA0D /* Release */, 328 | ); 329 | defaultConfigurationIsVisible = 0; 330 | defaultConfigurationName = Release; 331 | }; 332 | /* End XCConfigurationList section */ 333 | }; 334 | rootObject = 8D20BF02179FEC7E0093BA0D /* Project object */; 335 | } 336 | -------------------------------------------------------------------------------- /HTCopyableLabelDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /HTCopyableLabelDemo.xcodeproj/project.xcworkspace/xcshareddata/HTCopyableLabelDemo.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectIdentifier 6 | 7344E016-79EB-4481-BCC9-EF3074B36CBD 7 | IDESourceControlProjectName 8 | HTCopyableLabelDemo 9 | IDESourceControlProjectOriginsDictionary 10 | 11 | 7697120B-E0AC-4D9A-BE25-A19067E1FF27 12 | ssh://github.com/hoteltonight/HTCopyableLabel.git 13 | 14 | IDESourceControlProjectPath 15 | HTCopyableLabelDemo.xcodeproj/project.xcworkspace 16 | IDESourceControlProjectRelativeInstallPathDictionary 17 | 18 | 7697120B-E0AC-4D9A-BE25-A19067E1FF27 19 | ../.. 20 | 21 | IDESourceControlProjectURL 22 | ssh://github.com/hoteltonight/HTCopyableLabel.git 23 | IDESourceControlProjectVersion 24 | 110 25 | IDESourceControlProjectWCCIdentifier 26 | 7697120B-E0AC-4D9A-BE25-A19067E1FF27 27 | IDESourceControlProjectWCConfigurations 28 | 29 | 30 | IDESourceControlRepositoryExtensionIdentifierKey 31 | public.vcs.git 32 | IDESourceControlWCCIdentifierKey 33 | 7697120B-E0AC-4D9A-BE25-A19067E1FF27 34 | IDESourceControlWCCName 35 | HTCopyableLabelDemo 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /HTCopyableLabelDemo.xcodeproj/xcuserdata/jonsibley.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /HTCopyableLabelDemo.xcodeproj/xcuserdata/jonsibley.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /HTCopyableLabelDemo.xcodeproj/xcuserdata/jonsibley.xcuserdatad/xcschemes/HTCopyableLabelDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 51 | 52 | 58 | 59 | 60 | 61 | 62 | 63 | 69 | 70 | 76 | 77 | 78 | 79 | 81 | 82 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /HTCopyableLabelDemo.xcodeproj/xcuserdata/jonsibley.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | HTCopyableLabelDemo.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 8D20BF09179FEC7E0093BA0D 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /HTCopyableLabelDemo/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoteltonight/HTCopyableLabel/9437c10c402e5c227991b9af4fa26b31b04d3136/HTCopyableLabelDemo/Default-568h@2x.png -------------------------------------------------------------------------------- /HTCopyableLabelDemo/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoteltonight/HTCopyableLabel/9437c10c402e5c227991b9af4fa26b31b04d3136/HTCopyableLabelDemo/Default.png -------------------------------------------------------------------------------- /HTCopyableLabelDemo/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoteltonight/HTCopyableLabel/9437c10c402e5c227991b9af4fa26b31b04d3136/HTCopyableLabelDemo/Default@2x.png -------------------------------------------------------------------------------- /HTCopyableLabelDemo/HTAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // HTAppDelegate.h 3 | // HTCopyableLabelDemo 4 | // 5 | // Created by Jonathan Sibley on 7/24/13. 6 | // Copyright (c) 2013 HotelTonight. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface HTAppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /HTCopyableLabelDemo/HTAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // HTAppDelegate.m 3 | // HTCopyableLabelDemo 4 | // 5 | // Created by Jonathan Sibley on 7/24/13. 6 | // Copyright (c) 2013 HotelTonight. All rights reserved. 7 | // 8 | 9 | #import "HTAppDelegate.h" 10 | 11 | @implementation HTAppDelegate 12 | 13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 14 | { 15 | // Override point for customization after application launch. 16 | return YES; 17 | } 18 | 19 | - (void)applicationWillResignActive:(UIApplication *)application 20 | { 21 | // 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. 22 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 23 | } 24 | 25 | - (void)applicationDidEnterBackground:(UIApplication *)application 26 | { 27 | // 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. 28 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 29 | } 30 | 31 | - (void)applicationWillEnterForeground:(UIApplication *)application 32 | { 33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | - (void)applicationDidBecomeActive:(UIApplication *)application 37 | { 38 | // 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. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application 42 | { 43 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /HTCopyableLabelDemo/HTCopyableLabelDemo-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.hoteltonight.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIMainStoryboardFile 28 | MainStoryboard 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /HTCopyableLabelDemo/HTCopyableLabelDemo-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'HTCopyableLabelDemo' target in the 'HTCopyableLabelDemo' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_5_0 8 | #warning "This project uses features only available in iOS SDK 5.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | -------------------------------------------------------------------------------- /HTCopyableLabelDemo/HTPasteViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // HTPasteViewController.h 3 | // HTCopyableLabelDemo 4 | // 5 | // Created by Jonathan Sibley on 7/24/13. 6 | // Copyright (c) 2013 HotelTonight. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface HTPasteViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /HTCopyableLabelDemo/HTPasteViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // HTPasteViewController.m 3 | // HTCopyableLabelDemo 4 | // 5 | // Created by Jonathan Sibley on 7/24/13. 6 | // Copyright (c) 2013 HotelTonight. All rights reserved. 7 | // 8 | 9 | #import "HTPasteViewController.h" 10 | 11 | @interface HTPasteViewController () 12 | 13 | @property (weak, nonatomic) IBOutlet UITextView *textView; 14 | 15 | @end 16 | 17 | @implementation HTPasteViewController 18 | 19 | - (IBAction)dismissKeyboard:(id)sender 20 | { 21 | [self.textView resignFirstResponder]; 22 | } 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /HTCopyableLabelDemo/HTViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // HTViewController.h 3 | // HTCopyableLabelDemo 4 | // 5 | // Created by Jonathan Sibley on 7/24/13. 6 | // Copyright (c) 2013 HotelTonight. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface HTViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /HTCopyableLabelDemo/HTViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // HTViewController.m 3 | // HTCopyableLabelDemo 4 | // 5 | // Created by Jonathan Sibley on 7/24/13. 6 | // Copyright (c) 2013 HotelTonight. All rights reserved. 7 | // 8 | 9 | #import "HTViewController.h" 10 | #import "HTCopyableLabel.h" 11 | 12 | @interface HTViewController () 13 | 14 | @property (nonatomic, weak) IBOutlet HTCopyableLabel *label1; 15 | 16 | @property (nonatomic, weak) IBOutlet UIView *labelContainer1; 17 | @property (nonatomic, weak) IBOutlet HTCopyableLabel *label2; 18 | @property (nonatomic, weak) IBOutlet HTCopyableLabel *label3; 19 | @property (nonatomic, weak) IBOutlet HTCopyableLabel *label4; 20 | 21 | @property (nonatomic, weak) IBOutlet UIView *labelContainer2; 22 | @property (nonatomic, weak) IBOutlet HTCopyableLabel *label5; 23 | 24 | @end 25 | 26 | @implementation HTViewController 27 | 28 | - (void)viewDidLoad 29 | { 30 | [super viewDidLoad]; 31 | 32 | self.label2.copyableLabelDelegate = self; 33 | self.label3.copyableLabelDelegate = self; 34 | self.label4.copyableLabelDelegate = self; 35 | 36 | self.label5.copyableLabelDelegate = self; 37 | [self.labelContainer2 addGestureRecognizer:self.label5.longPressGestureRecognizer]; 38 | } 39 | 40 | #pragma mark - HTCopyableLabelDelegate 41 | 42 | - (NSString *)stringToCopyForCopyableLabel:(HTCopyableLabel *)copyableLabel 43 | { 44 | NSString *stringToCopy = @""; 45 | 46 | if (copyableLabel == self.label2 47 | || copyableLabel == self.label3 48 | || copyableLabel == self.label4) 49 | { 50 | stringToCopy = [NSString stringWithFormat:@"%@\n\n%@\n\n%@", self.label2.text, self.label3.text, self.label4.text]; 51 | } 52 | else if (copyableLabel == self.label5) 53 | { 54 | stringToCopy = self.label5.text; 55 | } 56 | 57 | return stringToCopy; 58 | } 59 | 60 | - (CGRect)copyMenuTargetRectInCopyableLabelCoordinates:(HTCopyableLabel *)copyableLabel 61 | { 62 | CGRect rect; 63 | 64 | if (copyableLabel == self.label2 65 | || copyableLabel == self.label3 66 | || copyableLabel == self.label4) 67 | { 68 | // The UIMenuController will appear close to container, indicating all of its contents will be copied 69 | rect = [self.labelContainer1 convertRect:self.labelContainer1.bounds toView:copyableLabel]; 70 | } 71 | else if (copyableLabel == self.label5) 72 | { 73 | // The UIMenuController will appear close to the label itself 74 | rect = copyableLabel.bounds; 75 | } 76 | 77 | return rect; 78 | } 79 | 80 | @end 81 | -------------------------------------------------------------------------------- /HTCopyableLabelDemo/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /HTCopyableLabelDemo/en.lproj/MainStoryboard.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 27 | 28 | 29 | 30 | 40 | 47 | 54 | 60 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 100 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | -------------------------------------------------------------------------------- /HTCopyableLabelDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // HTCopyableLabelDemo 4 | // 5 | // Created by Jonathan Sibley on 7/24/13. 6 | // Copyright (c) 2013 HotelTonight. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "HTAppDelegate.h" 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([HTAppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Hotel Tonight Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | HTCopyableLabel 2 | =============== 3 | HotelTonight 4 | 5 | ## Overview 6 | 7 | HTCopyableLabel is a subclass of UILabel that makes it easy to allow users to copy a label's text. 8 | 9 | HotelTonight 10 | 11 | Read the accompanying [blog post](http://engineering.hoteltonight.com/htcopyablelabel/) on the [HotelTonight Engineering Blog](http://engineering.hoteltonight.com/). For an excellent explanation how copying on a UILabel is implemented, be sure to read [UIMenuController](http://nshipster.com/uimenucontroller/) on [NSHipster](http://nshipster.com). 12 | 13 | # Usage 14 | 15 | ## Installation 16 | 17 | ### With Cocoapods: 18 | * Add `pod 'HTCopyableLabel'` to your `Podfile` 19 | 20 | ### Without Cocoapods: 21 | Manually add the following files into your project: 22 | * `HTCopyableLabel.m` 23 | * `HTCopyableLabel.h` 24 | 25 | ## Quickstart Guide 26 | 27 | Create an `HTCopyableLabel` instance exactly as as you would `UILabel`, or subclass `HTCopyableLabel` if you'd like. You can do this or in Interface Builder. Programmatically, this looks like: 28 | 29 | HTCopyableLabel *copyableLabel = [[HTCopyableLabel alloc] init]; 30 | [self.view addSubview:copyableLabel]; 31 | 32 | Now, long pressing on the label will make a UIMenuController appear with a "Copy" option. Pressing "Copy" will copy the label's `text`. Make sure the superview of the label has `userInteractionEnabled` set to `YES`. 33 | 34 | ## Advanced Usage 35 | 36 | Implementing the `HTCopyableLabelDelegate` protocol allows you more fine-tuned control of the `UIMenuController`'s position, as well as the actual string that is to be copied. 37 | 38 | ### UIMenuController appearance and position 39 | 40 | `UIMenuController` positions itself according to a frame passed to it by `HTCopyableLabel`. By default, `HTCopyableLabel` will pass its own bounds. To specify the frame explicitly, implement the following in your `HTCopyableLabelDelegate`: 41 | 42 | - (CGRect)copyMenuTargetRectInCopyableLabelCoordinates:(HTCopyableLabel *)copyableLabel 43 | 44 | Furthermore, `UIMenuController` will try to intelligently position itself above, below, or along side the frame you pass it according to its position within the screen. If you wish to override this behavior, you should set `[HTCopyableLabel copyMenuArrowDirection]` explicitly. 45 | 46 | ### Specifying the text to be copied 47 | 48 | If you wish to specify which string is copied to the pasteboard, implement the following method in your `HTCopyableLabelDelegate`: 49 | 50 | - (NSString *)stringToCopyForCopyableLabel:(HTCopyableLabel *)copyableLabel 51 | 52 | # Etc. 53 | 54 | * Use this in your apps whenever you can, particularly email addresses -- your users will appreciate it! 55 | * Contributions are very welcome. 56 | * Attribution is appreciated (let's spread the word!), but not mandatory. 57 | 58 | ## Use it? Love/hate it? 59 | 60 | Tweet the author [@jonsibs](https://twitter.com/jonsibs), and check out HotelTonight's engineering blog: http://engineering.hoteltonight.com 61 | 62 | Also, check out HotelTonight's other iOS open source: 63 | * https://github.com/hoteltonight/HTAutocompleteTextField 64 | * https://github.com/hoteltonight/HTGradientEasing 65 | * https://github.com/hoteltonight/HTStateAwareRasterImageView 66 | * https://github.com/hoteltonight/HTDelegateProxy 67 | -------------------------------------------------------------------------------- /demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoteltonight/HTCopyableLabel/9437c10c402e5c227991b9af4fa26b31b04d3136/demo.gif -------------------------------------------------------------------------------- /ht-logo-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoteltonight/HTCopyableLabel/9437c10c402e5c227991b9af4fa26b31b04d3136/ht-logo-black.png --------------------------------------------------------------------------------