diff --git a/KILabel.podspec.json b/KILabel.podspec.json new file mode 100644 index 0000000..3ad12e9 --- /dev/null +++ b/KILabel.podspec.json @@ -0,0 +1,27 @@ +{ + "name": "KILabel", + "version": "0.1.0", + "summary": "UILabel with higlighting options", + "description": "Subclass of UILabel that performs automatic url highlithging", + "homepage": "https://github.com/mobilejazz/KILabel", + "license": { + "type": "Apache License, Version 2.0", + "file": "LICENSE" + }, + "authors": { + "Mobile Jazz": "info@mobilejazz.cat" + }, + "social_media_url": "http://twitter.com/mobilejazzcat", + "source": { + "git": "https://github.com/mobilejazz/KILabel.git", + "tag": "0.1.0" + }, + "source_files": [ + "KILabel/Source/KILabel.{h,m}" + ], + "platforms": { + "ios": "7.0" + }, + "frameworks": "Foundation", + "requires_arc": true +} diff --git a/KILabel/Source/KILabel.h b/KILabel/Source/KILabel.h index dd3e0a5..d8cb6c3 100644 --- a/KILabel/Source/KILabel.h +++ b/KILabel/Source/KILabel.h @@ -25,53 +25,116 @@ #import - -// Constants for identifying link types -typedef NS_ENUM(NSInteger, KILinkType) -{ - KILinkTypeUserHandle, - KILinkTypeHashtag, - KILinkTypeURL -}; - // Constants for identifying link types we can detect -typedef NS_OPTIONS(NSUInteger, KILinkDetectionTypes) +typedef NS_OPTIONS(NSUInteger, KILinkType) { - KILinkDetectionTypeUserHandle = (1 << 0), - KILinkDetectionTypeHashtag = (1 << 1), - KILinkDetectionTypeURL = (1 << 2), + KILinkTypeNone = 0, - // Convenient constants - KILinkDetectionTypeNone = 0, - KILinkDetectionTypeAll = NSUIntegerMax + KILinkTypeUserHandle = 1 << 0, + KILinkTypeHashtag = 1 << 1, + KILinkTypeURL = 1 << 2, + + KILinkTypeAll = NSUIntegerMax, }; - +@class KILabel; // Block method that is called when an interactive word is touched -typedef void (^KILinkTapHandler)(KILinkType linkType, NSString *string, NSRange range); - +typedef void (^KILinkTapHandler)(KILabel *label, NSString *string, NSRange range); +extern NSString * const KILabelLinkTypeKey; +extern NSString * const KILabelRangeKey; +extern NSString * const KILabelLinkKey; +/** + * Smart UILabel subclass that detects links, hashtags and usernames. + **/ @interface KILabel : UILabel -// Automatic detection of links, hashtags and usernames. When this is enabled links -// are coloured using the views tintColor property. +/** ****************************************************************************************** ** + * @name Setting the link detector + ** ****************************************************************************************** **/ + +/** + * Automatic detection of links, hashtags and usernames. + **/ @property (nonatomic, assign, getter = isAutomaticLinkDetectionEnabled) BOOL automaticLinkDetectionEnabled; -@property (nonatomic, assign) KILinkDetectionTypes linkDetectionTypes; +/** + * The link types to detect. Default value is KILinkTypeAll. + **/ +@property (nonatomic, assign) KILinkType linkDetectionTypes; -// Colour used to hilight selected link background -@property (nonatomic, copy) UIColor *selectedLinkBackgroundColour; +/** + * Set containing words to be ignored as links, hashtags or usernames. + * @discussion The comparison between the matches and the ignored words is case insensitive. + **/ +@property (nonatomic, strong) NSSet *ignoredKeywords; + +/** ****************************************************************************************** ** + * @name Format & Appearance + ** ****************************************************************************************** **/ -// Get or set a block that is called when a link is touched -@property (nonatomic, copy) KILinkTapHandler linkTapHandler; +/** + * Colour used to highlight selected link background. Default value is nil (none). + **/ +@property (nonatomic, copy) UIColor *selectedLinkBackgroundColour; -// Returns a dictionary of data about the link that it at the location. Returns -// nil if there is no link. A link dictionary contains the following keys: -// @"linkType" a TDLinkType that identifies the type of link -// @"range" the range of the link within the label text -// @"link" the link text. This could be an URL, handle or hashtag depending on the linkType value -- (NSDictionary *)getLinkAtLocation:(CGPoint)location; +/** + * Flag to use the sytem format for URLs (underlined + blue color). Default value is NO. + **/ +@property (nonatomic, assign) BOOL systemURLStyle; + +/** + * Get the current attributes for the given link type. + * @param linkType The link type to get the attributes. + * @return A dictionary of text attributes. + * @discussion Default attributes contain colored font using the tintColor color property + **/ +- (NSDictionary*)attributesForLinkType:(KILinkType)linkType; + +/** + * Set the text attributes for each link type. + * @param attributes The text attributes. + * @param linkType The link type. + * @discussion Default attributes contain colored font using the tintColor color property. + **/ +- (void)setAttributes:(NSDictionary*)attributes forLinkType:(KILinkType)linkType; + +/** ****************************************************************************************** ** + * @name Callbacks + ** ****************************************************************************************** **/ + +/** + * Callback block for KILinkTypeUserHandle link tap. + **/ +@property (nonatomic, copy) KILinkTapHandler linkUserHandleTapHandler; + +/** + * Callback block for KILinkTypeHashtag link tap. + **/ +@property (nonatomic, copy) KILinkTapHandler linkHashtagTapHandler; + +/** + * Callback block for KILinkTypeURL link tap. + **/ +@property (nonatomic, copy) KILinkTapHandler linkURLTapHandler; + +/** ****************************************************************************************** ** + * @name Geometry + ** ****************************************************************************************** **/ + +/** + * Returns a dictionary of data about the link that it at the location. Returns nil if there is no link. + * + * A link dictionary contains the following keys: + * KILabelLinkTypeKey: a TDLinkType that identifies the type of link. + * KILabelRangeKey: the range of the link within the label text. + * KILabelLinkKey: the link text. This could be an URL, handle or hashtag depending on the linkType value. + * + * @param point The point in the coordinates of the label view. + * @return A dictionary containing the link. + **/ +- (NSDictionary*)linkAtPoint:(CGPoint)point; @end diff --git a/KILabel/Source/KILabel.m b/KILabel/Source/KILabel.m index 05f4f11..35c13f2 100644 --- a/KILabel/Source/KILabel.m +++ b/KILabel/Source/KILabel.m @@ -25,6 +25,9 @@ #import "KILabel.h" +NSString * const KILabelLinkTypeKey = @"linkType"; +NSString * const KILabelRangeKey = @"range"; +NSString * const KILabelLinkKey = @"link"; #pragma mark - Private Interface @@ -50,10 +53,12 @@ @interface KILabel() @end - #pragma mark - Implementation @implementation KILabel +{ + NSMutableDictionary *_linkTypeAttributes; +} #pragma mark - Construction @@ -81,19 +86,19 @@ - (id)initWithCoder:(NSCoder *)aDecoder - (void)setupTextSystem { // Create a text container and set it up to match our label properties - self.textContainer = [[NSTextContainer alloc] init]; - self.textContainer.lineFragmentPadding = 0; - self.textContainer.maximumNumberOfLines = self.numberOfLines; - self.textContainer.lineBreakMode = self.lineBreakMode; - self.textContainer.size = self.frame.size; + _textContainer = [[NSTextContainer alloc] init]; + _textContainer.lineFragmentPadding = 0; + _textContainer.maximumNumberOfLines = self.numberOfLines; + _textContainer.lineBreakMode = self.lineBreakMode; + _textContainer.size = self.frame.size; // Create a layout manager for rendering - self.layoutManager = [[NSLayoutManager alloc] init]; - self.layoutManager.delegate = self; - [self.layoutManager addTextContainer:self.textContainer]; + _layoutManager = [[NSLayoutManager alloc] init]; + _layoutManager.delegate = self; + [_layoutManager addTextContainer:_textContainer]; // Attach the layou manager to the container and storage - [self.textContainer setLayoutManager:self.layoutManager]; + [_textContainer setLayoutManager:_layoutManager]; // Make sure user interaction is enabled so we can accept touches self.userInteractionEnabled = YES; @@ -102,37 +107,20 @@ - (void)setupTextSystem _automaticLinkDetectionEnabled = YES; // All links are detectable by default - _linkDetectionTypes = KILinkDetectionTypeAll; + _linkDetectionTypes = KILinkTypeAll; - // Default background colour looks good on a white background - self.selectedLinkBackgroundColour = [UIColor colorWithWhite:0.95 alpha:1.0]; + // Link Type Attributes. Default is empty (no attributes). + _linkTypeAttributes = [NSMutableDictionary dictionary]; + + // Don't underline URL links by default. + _systemURLStyle = NO; + + _selectedLinkBackgroundColour = nil;//[UIColor colorWithWhite:0.95 alpha:1.0]; // Establish the text store with our current text [self updateTextStoreWithText]; - - // Attach a default detection handler to help with debugging - self.linkTapHandler = ^(KILinkType linkType, NSString *string, NSRange range) { - NSString *linkTypeName = nil; - switch (linkType) - { - case KILinkTypeUserHandle: - linkTypeName = @"KILinkTypeUserHandle"; - break; - - case KILinkTypeHashtag: - linkTypeName = @"KILinkTypeHashtag"; - break; - - case KILinkTypeURL: - linkTypeName = @"KILinkTypeURL"; - break; - } - - NSLog(@"Default handler for label: %@, %@, (%lu, %lu)", linkTypeName, string, (unsigned long)range.location, (unsigned long)range.length); - }; } - #pragma mark - Text and Style management - (void)setAutomaticLinkDetectionEnabled:(BOOL)decorating @@ -143,7 +131,7 @@ - (void)setAutomaticLinkDetectionEnabled:(BOOL)decorating [self updateTextStoreWithText]; } -- (void)setLinkDetectionTypes:(KILinkDetectionTypes)linkDetectionTypes +- (void)setLinkDetectionTypes:(KILinkType)linkDetectionTypes { _linkDetectionTypes = linkDetectionTypes; @@ -151,43 +139,37 @@ - (void)setLinkDetectionTypes:(KILinkDetectionTypes)linkDetectionTypes [self updateTextStoreWithText]; } -- (NSDictionary *)getLinkAtLocation:(CGPoint)location +- (NSDictionary *)linkAtPoint:(CGPoint)location { // Do nothing if we have no text - if (self.textStorage.string.length == 0) - { + if (_textStorage.string.length == 0) return nil; - } // Work out the offset of the text in the view CGPoint textOffset; - NSRange glyphRange = [self.layoutManager glyphRangeForTextContainer:self.textContainer]; + NSRange glyphRange = [_layoutManager glyphRangeForTextContainer:_textContainer]; textOffset = [self calcTextOffsetForGlyphRange:glyphRange]; // Get the touch location and use text offset to convert to text cotainer coords location.x -= textOffset.x; location.y -= textOffset.y; - NSUInteger touchedChar = [self.layoutManager glyphIndexForPoint:location inTextContainer:self.textContainer]; + NSUInteger touchedChar = [_layoutManager glyphIndexForPoint:location inTextContainer:_textContainer]; // If the touch is in white space after the last glyph on the line we don't // count it as a hit on the text NSRange lineRange; - CGRect lineRect = [self.layoutManager lineFragmentUsedRectForGlyphAtIndex:touchedChar effectiveRange:&lineRange]; + CGRect lineRect = [_layoutManager lineFragmentUsedRectForGlyphAtIndex:touchedChar effectiveRange:&lineRange]; if (CGRectContainsPoint(lineRect, location) == NO) - { return nil; - } // Find the word that was touched and call the detection block for (NSDictionary *dictionary in self.linkRanges) { - NSRange range = [[dictionary objectForKey:@"range"] rangeValue]; + NSRange range = [[dictionary objectForKey:KILabelRangeKey] rangeValue]; if ((touchedChar >= range.location) && touchedChar < (range.location + range.length)) - { return dictionary; - } } return nil; @@ -198,18 +180,11 @@ - (void)setSelectedRange:(NSRange)range { // Remove the current selection if the selection is changing if (self.selectedRange.length && !NSEqualRanges(self.selectedRange, range)) - { - [self.textStorage removeAttribute:NSBackgroundColorAttributeName - range:self.selectedRange]; - } + [_textStorage removeAttribute:NSBackgroundColorAttributeName range:self.selectedRange]; // Apply the new selection to the text - if (range.length) - { - [self.textStorage addAttribute:NSBackgroundColorAttributeName - value:self.selectedLinkBackgroundColour - range:range]; - } + if (range.length && _selectedLinkBackgroundColour != nil) + [_textStorage addAttribute:NSBackgroundColorAttributeName value:_selectedLinkBackgroundColour range:range]; // Save the new range _selectedRange = range; @@ -221,7 +196,7 @@ - (void)setNumberOfLines:(NSInteger)numberOfLines { [super setNumberOfLines:numberOfLines]; - self.textContainer.maximumNumberOfLines = numberOfLines; + _textContainer.maximumNumberOfLines = numberOfLines; } - (void)setText:(NSString *)text @@ -231,8 +206,10 @@ - (void)setText:(NSString *)text // Update our text store with an attributed string based on the original // label text properties. - NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:text - attributes:[self attributesFromProperties]]; + if (!text) + text = @""; + + NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:text attributes:[self attributesFromProperties]]; [self updateTextStoreWithAttributedString:attributedText]; } @@ -244,24 +221,47 @@ - (void)setAttributedText:(NSAttributedString *)attributedText [self updateTextStoreWithAttributedString:attributedText]; } +- (void)setSystemURLStyle:(BOOL)systemURLStyle +{ + _systemURLStyle = systemURLStyle; + + // Force refresh + self.text = self.text; +} + +- (NSDictionary*)attributesForLinkType:(KILinkType)linkType +{ + NSDictionary *attributes = _linkTypeAttributes[@(linkType)]; + + if (!attributes) + attributes = @{NSForegroundColorAttributeName : self.tintColor}; + + return attributes; +} + +- (void)setAttributes:(NSDictionary*)attributes forLinkType:(KILinkType)linkType +{ + if (attributes) + _linkTypeAttributes[@(linkType)] = attributes; + else + [_linkTypeAttributes removeObjectForKey:@(linkType)]; + + // Force refresh text + self.text = self.text; +} + #pragma mark - Text Storage Management - (void)updateTextStoreWithText { // Now update our storage from either the attributedString or the plain text if (self.attributedText) - { [self updateTextStoreWithAttributedString:self.attributedText]; - } else if (self.text) - { [self updateTextStoreWithAttributedString:[[NSAttributedString alloc] initWithString:self.text attributes:[self attributesFromProperties]]]; - } else - { [self updateTextStoreWithAttributedString:[[NSAttributedString alloc] initWithString:@"" attributes:[self attributesFromProperties]]]; - } - + [self setNeedsDisplay]; } @@ -282,17 +282,17 @@ - (void)updateTextStoreWithAttributedString:(NSAttributedString *)attributedStri self.linkRanges = nil; } - if (self.textStorage) + if (_textStorage) { // Set the string on the storage - [self.textStorage setAttributedString:attributedString]; + [_textStorage setAttributedString:attributedString]; } else { // Create a new text storage and attach it correctly to the layout manager - self.textStorage = [[NSTextStorage alloc] initWithAttributedString:attributedString]; - [self.textStorage addLayoutManager:self.layoutManager]; - [self.layoutManager setTextStorage:self.textStorage]; + _textStorage = [[NSTextStorage alloc] initWithAttributedString:attributedString]; + [_textStorage addLayoutManager:_layoutManager]; + [_layoutManager setTextStorage:_textStorage]; } } @@ -316,24 +316,20 @@ - (NSDictionary *)attributesFromProperties // Setup colour attributes UIColor *colour = self.textColor; if (!self.isEnabled) - { colour = [UIColor lightGrayColor]; - } else if (self.isHighlighted) - { colour = self.highlightedTextColor; - } // Setup paragraph attributes NSMutableParagraphStyle *paragraph = [[NSMutableParagraphStyle alloc] init]; paragraph.alignment = self.textAlignment; // Create the dictionary - NSDictionary *attributes = @{ - NSFontAttributeName : self.font, + NSDictionary *attributes = @{NSFontAttributeName : self.font, NSForegroundColorAttributeName : colour, NSShadowAttributeName : shadow, - NSParagraphStyleAttributeName : paragraph }; + NSParagraphStyleAttributeName : paragraph, + }; return attributes; } @@ -342,20 +338,14 @@ - (NSArray *)getRangesForLinks:(NSAttributedString *)text { NSMutableArray *rangesForLinks = [[NSMutableArray alloc] init]; - if (self.linkDetectionTypes & KILinkDetectionTypeUserHandle) - { + if (self.linkDetectionTypes & KILinkTypeUserHandle) [rangesForLinks addObjectsFromArray:[self getRangesForUserHandles:text.string]]; - } - if (self.linkDetectionTypes & KILinkDetectionTypeHashtag) - { + if (self.linkDetectionTypes & KILinkTypeHashtag) [rangesForLinks addObjectsFromArray:[self getRangesForHashtags:text.string]]; - } - if (self.linkDetectionTypes & KILinkDetectionTypeURL) - { + if (self.linkDetectionTypes & KILinkTypeURL) [rangesForLinks addObjectsFromArray:[self getRangesForURLs:self.attributedText]]; - } return rangesForLinks; } @@ -365,26 +355,27 @@ - (NSArray *)getRangesForUserHandles:(NSString *)text NSMutableArray *rangesForUserHandles = [[NSMutableArray alloc] init]; // Setup a regular expression for user handles and hashtags - NSError *error = nil; - NSRegularExpression *regex = [[NSRegularExpression alloc] initWithPattern:@"(? 0) - { textOffset.y = paddingHeight; - } return textOffset; } @@ -558,13 +551,13 @@ - (CGPoint)calcTextOffsetForGlyphRange:(NSRange)glyphRange - (void)setFrame:(CGRect)frame { [super setFrame:frame]; - self.textContainer.size = self.bounds.size; + _textContainer.size = self.bounds.size; } - (void)setBounds:(CGRect)bounds { [super setBounds:bounds]; - self.textContainer.size = self.bounds.size; + _textContainer.size = self.bounds.size; } - (void)layoutSubviews @@ -572,36 +565,42 @@ - (void)layoutSubviews [super layoutSubviews]; // Update our container size when the view frame changes - self.textContainer.size = self.bounds.size; + _textContainer.size = self.bounds.size; } +- (void)setIgnoredKeywords:(NSSet *)ignoredKeywords +{ + NSMutableSet *set = [NSMutableSet setWithCapacity:ignoredKeywords.count]; + + [ignoredKeywords enumerateObjectsUsingBlock:^(id obj, BOOL *stop) { + [set addObject:[obj lowercaseString]]; + }]; + + _ignoredKeywords = [set copy]; +} #pragma mark - Interactions - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { - self.isTouchMoved = NO; + _isTouchMoved = NO; // Get the info for the touched link if there is one NSDictionary *touchedLink; CGPoint touchLocation = [[touches anyObject] locationInView:self]; - touchedLink = [self getLinkAtLocation:touchLocation]; + touchedLink = [self linkAtPoint:touchLocation]; if (touchedLink) - { - self.selectedRange = [[touchedLink objectForKey:@"range"] rangeValue]; - } + self.selectedRange = [[touchedLink objectForKey:KILabelRangeKey] rangeValue]; else - { [super touchesBegan:touches withEvent:event]; - } } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesMoved:touches withEvent:event]; - self.isTouchMoved = YES; + _isTouchMoved = YES; } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event @@ -609,25 +608,24 @@ - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event [super touchesEnded:touches withEvent:event]; // If the user dragged their finger we ignore the touch - if (self.isTouchMoved) + if (_isTouchMoved) { self.selectedRange = NSMakeRange(0, 0); - return; } // Get the info for the touched link if there is one NSDictionary *touchedLink; CGPoint touchLocation = [[touches anyObject] locationInView:self]; - touchedLink = [self getLinkAtLocation:touchLocation]; + touchedLink = [self linkAtPoint:touchLocation]; if (touchedLink) { - NSRange range = [[touchedLink objectForKey:@"range"] rangeValue]; - NSString *touchedSubstring = [touchedLink objectForKey:@"link"]; - KILinkType linkType = (KILinkType)[[touchedLink objectForKey:@"linkType"] intValue]; + NSRange range = [[touchedLink objectForKey:KILabelRangeKey] rangeValue]; + NSString *touchedSubstring = [touchedLink objectForKey:KILabelLinkKey]; + KILinkType linkType = (KILinkType)[[touchedLink objectForKey:KILabelLinkTypeKey] intValue]; - self.linkTapHandler(linkType, touchedSubstring, range); + [self receivedActionForLinkType:linkType string:touchedSubstring range:range]; } else { @@ -645,6 +643,24 @@ - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event self.selectedRange = NSMakeRange(0, 0); } +- (void)receivedActionForLinkType:(KILinkType)linkType string:(NSString*)string range:(NSRange)range +{ + if (linkType == KILinkTypeUserHandle) + { + if (_linkUserHandleTapHandler) + _linkUserHandleTapHandler(self, string, range); + } + else if (linkType == KILinkTypeHashtag) + { + if (_linkHashtagTapHandler) + _linkHashtagTapHandler(self, string, range); + } + else if (linkType == KILinkTypeURL) + { + if (_linkURLTapHandler) + _linkURLTapHandler(self, string, range); + } +} #pragma mark - Layout manager delegate @@ -652,9 +668,7 @@ -(BOOL)layoutManager:(NSLayoutManager *)layoutManager shouldBreakLineByWordBefor { // Don't allow line breaks inside URLs NSRange range; - NSURL *linkURL = [layoutManager.textStorage attribute:NSLinkAttributeName - atIndex:charIndex - effectiveRange:&range]; + NSURL *linkURL = [layoutManager.textStorage attribute:NSLinkAttributeName atIndex:charIndex effectiveRange:&range]; return !(linkURL && (charIndex > range.location) && (charIndex <= NSMaxRange(range))); } @@ -673,9 +687,7 @@ + (NSAttributedString *)sanitizeAttributedString:(NSAttributedString *)attribute NSParagraphStyle *paragraphStyle = [attributedString attribute:NSParagraphStyleAttributeName atIndex:0 effectiveRange:&range]; if (paragraphStyle == nil) - { return attributedString; - } // Remove the line breaks NSMutableParagraphStyle *mutableParagraphStyle = [paragraphStyle mutableCopy]; @@ -688,5 +700,4 @@ + (NSAttributedString *)sanitizeAttributedString:(NSAttributedString *)attribute return restyled; } - @end diff --git a/KILabelDemo/KILabelDemo.xcodeproj/project.pbxproj b/KILabelDemo/KILabelDemo.xcodeproj/project.pbxproj index 742bed9..f389828 100644 --- a/KILabelDemo/KILabelDemo.xcodeproj/project.pbxproj +++ b/KILabelDemo/KILabelDemo.xcodeproj/project.pbxproj @@ -214,7 +214,7 @@ isa = PBXProject; attributes = { CLASSPREFIX = KI; - LastUpgradeCheck = 0500; + LastUpgradeCheck = 0510; ORGANIZATIONNAME = "Matthew Styles"; TargetAttributes = { C97DB30A183A56F00028EA5C = { @@ -324,7 +324,6 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; @@ -363,7 +362,6 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; @@ -421,7 +419,6 @@ C97DB320183A56F00028EA5C /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/KILabelDemo.app/KILabelDemo"; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", @@ -444,7 +441,6 @@ C97DB321183A56F00028EA5C /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/KILabelDemo.app/KILabelDemo"; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", @@ -479,6 +475,7 @@ C97DB31E183A56F00028EA5C /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; C97DB31F183A56F00028EA5C /* Build configuration list for PBXNativeTarget "KILabelDemoTests" */ = { isa = XCConfigurationList; @@ -487,6 +484,7 @@ C97DB321183A56F00028EA5C /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/KILabelDemo/KILabelDemo/KIViewController.m b/KILabelDemo/KILabelDemo/KIViewController.m index 6fdd41c..476911f 100644 --- a/KILabelDemo/KILabelDemo/KIViewController.m +++ b/KILabelDemo/KILabelDemo/KIViewController.m @@ -49,29 +49,33 @@ - (void)viewDidLoad // Attach a simple tap handler to the label. This is a quick and dirty way // to respond to links being touched by the user. - self.label.linkTapHandler = ^(KILinkType linkType, NSString *string, NSRange range) { - if (linkType == KILinkTypeURL) - { - // Open URLs - [self attemptOpenURL:[NSURL URLWithString:string]]; - } - else - { - // Put up an alert with a message if it's not an URL - NSString *linkTypeString = @"Username"; - if (linkType == KILinkTypeHashtag) - { - linkTypeString = @"Hashtag"; - } - - NSString *message = [NSString stringWithFormat:@"You tapped %@ which is a %@", string, linkTypeString]; - UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Hello" - message:message - delegate:nil - cancelButtonTitle:@"Dismiss" - otherButtonTitles:nil]; - [alert show]; - } + + _label.systemURLStyle = YES; + + _label.linkUserHandleTapHandler = ^(KILabel *label, NSString *string, NSRange range) { + NSString *message = [NSString stringWithFormat:@"You tapped %@", string]; + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Username" + message:message + delegate:nil + cancelButtonTitle:@"Dismiss" + otherButtonTitles:nil]; + [alert show]; + }; + + _label.linkHashtagTapHandler = ^(KILabel *label, NSString *string, NSRange range) { + NSString *message = [NSString stringWithFormat:@"You tapped %@", string]; + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Hashtag" + message:message + delegate:nil + cancelButtonTitle:@"Dismiss" + otherButtonTitles:nil]; + [alert show]; + + }; + + _label.linkURLTapHandler = ^(KILabel *label, NSString *string, NSRange range) { + // Open URLs + [self attemptOpenURL:[NSURL URLWithString:string]]; }; } @@ -88,15 +92,13 @@ - (IBAction)longPressLabel:(UILongPressGestureRecognizer *)recognizer { // Only accept gestures on our label and only in the begin state if ((recognizer.view != self.label) || (recognizer.state != UIGestureRecognizerStateBegan)) - { return; - } // Get the position of the touch in the label CGPoint location = [recognizer locationInView:self.label]; // Get the link under the location from the label - NSDictionary *link = [self.label getLinkAtLocation:location]; + NSDictionary *link = [self.label linkAtPoint:location]; if (!link) { @@ -127,37 +129,25 @@ - (IBAction)toggleDetectLinks:(UISwitch *)sender - (IBAction)toggleDetectURLs:(UISwitch *)sender { if (sender.isOn) - { - self.label.linkDetectionTypes |= KILinkDetectionTypeURL; - } + self.label.linkDetectionTypes |= KILinkTypeURL; else - { - self.label.linkDetectionTypes ^= KILinkDetectionTypeURL; - } + self.label.linkDetectionTypes ^= KILinkTypeURL; } - (IBAction)toggleDetectUsernames:(UISwitch *)sender { if (sender.isOn) - { - self.label.linkDetectionTypes |= KILinkDetectionTypeUserHandle; - } + self.label.linkDetectionTypes |= KILinkTypeUserHandle; else - { - self.label.linkDetectionTypes ^= KILinkDetectionTypeUserHandle; - } + self.label.linkDetectionTypes ^= KILinkTypeUserHandle; } - (IBAction)toggleDetectHashtags:(UISwitch *)sender { if (sender.isOn) - { - self.label.linkDetectionTypes |= KILinkDetectionTypeHashtag; - } + self.label.linkDetectionTypes |= KILinkTypeHashtag; else - { - self.label.linkDetectionTypes ^= KILinkDetectionTypeHashtag; - } + self.label.linkDetectionTypes ^= KILinkTypeHashtag; } #pragma mark - Action Sheet Delegate @@ -189,7 +179,7 @@ -(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger) [controller setSubject:@"Link from my App"]; // Create the body for the mail. We use HTML format because its nice - NSString *link = self.selectedLink[@"link"]; + NSString *link = self.selectedLink[KILabelLinkKey]; NSString *message = [NSString stringWithFormat:@"%@", link, link]; [controller setMessageBody:message isHTML:YES]; @@ -210,7 +200,7 @@ -(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger) case kActionOpenInSafari: { - NSURL *url = [NSURL URLWithString:self.selectedLink[@"link"]]; + NSURL *url = [NSURL URLWithString:self.selectedLink[KILabelLinkKey]]; [self attemptOpenURL:url]; break; } diff --git a/README.md b/README.md index 23d6b49..9e0e83d 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ KILabel doesn't have any special dependencies so just include the files from KIL * When using the **attributedText** property, KILabel will attempt to preserve the original attributes as much as possilbe. If you see any problems with this let me know. * The link hilighting and interaction can be enabled/disabled using the **automaticLinkDetectionEnabled** property. * The constructor always sets *userInteractionEnabled* to YES. If you subsequently set it NO you will lose the ability to interact with links even it **automaticLinkDetectionEnabled** is set to YES. -* Use the **getLinkAtLocation** method to find out if there is link text at a point in the label's coordinate system. This returns nil if there is no link at the location, otherwise returns a dictionary with the following keys: +* Use the **linkAtPoint** method to find out if there is link text at a point in the label's coordinate system. This returns nil if there is no link at the location, otherwise returns a dictionary with the following keys: * *linkType* a TDLinkType value that identifies the type of link * *range* an NSRange that gives the range of the link within the label's text * *link* an NSString containing the raw text of the link @@ -49,7 +49,7 @@ label.linkTapHandler = ^(KILinkType linkType, NSString *string, NSRange range) { Repository includes KILabelDemo that shows a simple use of the label in a storyboard with examples for implementing tappable links. -The demo also demonstrates how to use a gesture recognizer with the label to implement a long press on a link, which uses the **getLinkAtLocation|** method. +The demo also demonstrates how to use a gesture recognizer with the label to implement a long press on a link, which uses the **linkAtPoint** method. ## License & Credits