From b4de8024f04e84773af9727475b730621ea590b8 Mon Sep 17 00:00:00 2001 From: Jonas Gessner Date: Wed, 5 Feb 2014 21:47:00 +0100 Subject: [PATCH 1/4] Added long press event --- .../AttributedLabel Example.xccheckout | 41 +++++++++++++++++++ .../AttributedLabel Example.xccheckout | 41 +++++++++++++++++++ .../BasicDemo/BasicDemoViewController.m | 4 ++ .../CustomLinksViewController.m | 3 ++ .../TableViewDemoViewController.m | 4 ++ OHAttributedLabel/Source/OHAttributedLabel.h | 3 ++ OHAttributedLabel/Source/OHAttributedLabel.m | 36 +++++++++++++++- 7 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 AttributedLabel Example/AttributedLabel Example.xcodeproj/project.xcworkspace/xcshareddata/AttributedLabel Example.xccheckout create mode 100644 AttributedLabel Example/AttributedLabel Example.xcworkspace/xcshareddata/AttributedLabel Example.xccheckout diff --git a/AttributedLabel Example/AttributedLabel Example.xcodeproj/project.xcworkspace/xcshareddata/AttributedLabel Example.xccheckout b/AttributedLabel Example/AttributedLabel Example.xcodeproj/project.xcworkspace/xcshareddata/AttributedLabel Example.xccheckout new file mode 100644 index 0000000..1c3dadd --- /dev/null +++ b/AttributedLabel Example/AttributedLabel Example.xcodeproj/project.xcworkspace/xcshareddata/AttributedLabel Example.xccheckout @@ -0,0 +1,41 @@ + + + + + IDESourceControlProjectFavoriteDictionaryKey + + IDESourceControlProjectIdentifier + 8E00B687-E064-4809-8B28-8796809624B8 + IDESourceControlProjectName + AttributedLabel Example + IDESourceControlProjectOriginsDictionary + + C1454787-2CDA-4B38-A9B3-B2369AB9C48B + https://github.com/JonasGessner/OHAttributedLabel.git + + IDESourceControlProjectPath + AttributedLabel Example/AttributedLabel Example.xcodeproj/project.xcworkspace + IDESourceControlProjectRelativeInstallPathDictionary + + C1454787-2CDA-4B38-A9B3-B2369AB9C48B + ../../.. + + IDESourceControlProjectURL + https://github.com/JonasGessner/OHAttributedLabel.git + IDESourceControlProjectVersion + 110 + IDESourceControlProjectWCCIdentifier + C1454787-2CDA-4B38-A9B3-B2369AB9C48B + IDESourceControlProjectWCConfigurations + + + IDESourceControlRepositoryExtensionIdentifierKey + public.vcs.git + IDESourceControlWCCIdentifierKey + C1454787-2CDA-4B38-A9B3-B2369AB9C48B + IDESourceControlWCCName + OHAttributedLabel + + + + diff --git a/AttributedLabel Example/AttributedLabel Example.xcworkspace/xcshareddata/AttributedLabel Example.xccheckout b/AttributedLabel Example/AttributedLabel Example.xcworkspace/xcshareddata/AttributedLabel Example.xccheckout new file mode 100644 index 0000000..f033151 --- /dev/null +++ b/AttributedLabel Example/AttributedLabel Example.xcworkspace/xcshareddata/AttributedLabel Example.xccheckout @@ -0,0 +1,41 @@ + + + + + IDESourceControlProjectFavoriteDictionaryKey + + IDESourceControlProjectIdentifier + 183D72E1-D028-4B77-8A12-AC9BBB43440E + IDESourceControlProjectName + AttributedLabel Example + IDESourceControlProjectOriginsDictionary + + C1454787-2CDA-4B38-A9B3-B2369AB9C48B + https://github.com/JonasGessner/OHAttributedLabel.git + + IDESourceControlProjectPath + AttributedLabel Example/AttributedLabel Example.xcworkspace + IDESourceControlProjectRelativeInstallPathDictionary + + C1454787-2CDA-4B38-A9B3-B2369AB9C48B + ../.. + + IDESourceControlProjectURL + https://github.com/JonasGessner/OHAttributedLabel.git + IDESourceControlProjectVersion + 110 + IDESourceControlProjectWCCIdentifier + C1454787-2CDA-4B38-A9B3-B2369AB9C48B + IDESourceControlProjectWCConfigurations + + + IDESourceControlRepositoryExtensionIdentifierKey + public.vcs.git + IDESourceControlWCCIdentifierKey + C1454787-2CDA-4B38-A9B3-B2369AB9C48B + IDESourceControlWCCName + OHAttributedLabel + + + + diff --git a/AttributedLabel Example/Classes/BasicDemo/BasicDemoViewController.m b/AttributedLabel Example/Classes/BasicDemo/BasicDemoViewController.m index f6962dd..87b948d 100644 --- a/AttributedLabel Example/Classes/BasicDemo/BasicDemoViewController.m +++ b/AttributedLabel Example/Classes/BasicDemo/BasicDemoViewController.m @@ -175,6 +175,10 @@ -(UIColor*)attributedLabel:(OHAttributedLabel*)attrLabel colorForLink:(NSTextChe } } +- (void)attributedLabel:(OHAttributedLabel *)attributedLabel longPressedLink:(NSTextCheckingResult *)linkInfo { + NSLog(@"Long Pressed URL %@", linkInfo.URL); +} + -(BOOL)attributedLabel:(OHAttributedLabel *)attributedLabel shouldFollowLink:(NSTextCheckingResult *)linkInfo { [self.visitedLinks addObject:objectForLinkInfo(linkInfo)]; diff --git a/AttributedLabel Example/Classes/CustomLinksDemo/CustomLinksViewController.m b/AttributedLabel Example/Classes/CustomLinksDemo/CustomLinksViewController.m index 0e896a9..e0c4230 100644 --- a/AttributedLabel Example/Classes/CustomLinksDemo/CustomLinksViewController.m +++ b/AttributedLabel Example/Classes/CustomLinksDemo/CustomLinksViewController.m @@ -178,6 +178,9 @@ -(IBAction)changeLineSpacing:(UISlider*)slider #pragma mark - OHAttributedString Delegate Method ///////////////////////////////////////////////////////////////////////////// +- (void)attributedLabel:(OHAttributedLabel *)attributedLabel longPressedLink:(NSTextCheckingResult *)linkInfo { + NSLog(@"Long Pressed URL %@", linkInfo.URL); +} -(BOOL)attributedLabel:(OHAttributedLabel *)attributedLabel shouldFollowLink:(NSTextCheckingResult *)linkInfo { diff --git a/AttributedLabel Example/Classes/TableViewDemo/TableViewDemoViewController.m b/AttributedLabel Example/Classes/TableViewDemo/TableViewDemoViewController.m index 3742d5f..322d28a 100644 --- a/AttributedLabel Example/Classes/TableViewDemo/TableViewDemoViewController.m +++ b/AttributedLabel Example/Classes/TableViewDemo/TableViewDemoViewController.m @@ -141,6 +141,10 @@ -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath * #pragma mark - OHAttributedLabel Delegate Method ///////////////////////////////////////////////////////////////////////////// +- (void)attributedLabel:(OHAttributedLabel *)attributedLabel longPressedLink:(NSTextCheckingResult *)linkInfo { + NSLog(@"Long Pressed URL %@", linkInfo.URL); +} + -(BOOL)attributedLabel:(OHAttributedLabel *)attributedLabel shouldFollowLink:(NSTextCheckingResult *)linkInfo { if ([[UIApplication sharedApplication] canOpenURL:linkInfo.extendedURL]) diff --git a/OHAttributedLabel/Source/OHAttributedLabel.h b/OHAttributedLabel/Source/OHAttributedLabel.h index 7d43241..f16a3e7 100755 --- a/OHAttributedLabel/Source/OHAttributedLabel.h +++ b/OHAttributedLabel/Source/OHAttributedLabel.h @@ -39,6 +39,9 @@ @protocol OHAttributedLabelDelegate @optional -(BOOL)attributedLabel:(OHAttributedLabel*)attributedLabel shouldFollowLink:(NSTextCheckingResult*)linkInfo; + +-(void)attributedLabel:(OHAttributedLabel*)attributedLabel longPressedLink:(NSTextCheckingResult*)linkInfo; + //! @parameter underlineStyle Combination of CTUnderlineStyle and CTUnderlineStyleModifiers -(UIColor*)attributedLabel:(OHAttributedLabel*)attributedLabel colorForLink:(NSTextCheckingResult*)linkInfo underlineStyle:(int32_t*)underlineStyle; @end diff --git a/OHAttributedLabel/Source/OHAttributedLabel.m b/OHAttributedLabel/Source/OHAttributedLabel.m index 7053881..76c37f9 100755 --- a/OHAttributedLabel/Source/OHAttributedLabel.m +++ b/OHAttributedLabel/Source/OHAttributedLabel.m @@ -60,6 +60,7 @@ @interface OHAttributedLabel(/* Private */) NSMutableArray* _customLinks; CGPoint _touchStartPoint; UIGestureRecognizer *_gestureRecogniser; + UIGestureRecognizer *_longTapGestureReconizer; } @property(nonatomic, retain) NSTextCheckingResult* activeLink; -(NSTextCheckingResult*)linkAtCharacterIndex:(CFIndex)idx; @@ -146,6 +147,10 @@ - (void)commonInit _gestureRecogniser = [[OHTouchesGestureRecognizer alloc] initWithTarget:self action:@selector(_gestureRecognised:)]; _gestureRecogniser.delegate = self; [self addGestureRecognizer:_gestureRecogniser]; + + _longTapGestureReconizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)]; + _longTapGestureReconizer.delegate = self; + [self addGestureRecognizer:_longTapGestureReconizer]; } - (id) initWithFrame:(CGRect)aFrame @@ -442,6 +447,27 @@ -(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event return hitResult; } +- (void)longPress:(UILongPressGestureRecognizer *)gesture { + CGPoint pt = [gesture locationInView:self]; + + if (gesture.state == UIGestureRecognizerStateBegan) { + // Check that the link on touchEnd is the same as the link on touchBegan + NSTextCheckingResult* linkAtTouchesEnded = [self linkAtPoint:pt]; + BOOL closeToStart = (fabs(_touchStartPoint.x - pt.x) < 10 && fabs(_touchStartPoint.y - pt.y) < 10); + + // we must check on equality of the ranges themselves since the data detectors create new results + if (_activeLink && (NSEqualRanges(_activeLink.range,linkAtTouchesEnded.range) || closeToStart)) + { + // Same link on touchEnded than the one on touchBegan, so trigger it + [self processLongPressActiveLink]; + } + + gesture.enabled = NO; + gesture.enabled = YES; + } + +} + -(void)_gestureRecognised:(UIGestureRecognizer*)recogniser { CGPoint pt = [recogniser locationInView:self]; @@ -491,6 +517,14 @@ -(void)_gestureRecognised:(UIGestureRecognizer*)recogniser } } +- (void)processLongPressActiveLink { + NSTextCheckingResult* linkToOpen = _activeLink; + + if ([self.delegate respondsToSelector:@selector(attributedLabel:longPressedLink:)]) { + [self.delegate attributedLabel:self longPressedLink:linkToOpen]; + } +} + - (void)processActiveLink { NSTextCheckingResult* linkToOpen = _activeLink; @@ -677,7 +711,7 @@ - (CGSize)sizeThatFits:(CGSize)size ///////////////////////////////////////////////////////////////////////////////////// - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { - return ([[otherGestureRecognizer.view class] isSubclassOfClass:[UIScrollView class]]); + return (otherGestureRecognizer == _longTapGestureReconizer || otherGestureRecognizer == _gestureRecogniser || [[otherGestureRecognizer.view class] isSubclassOfClass:[UIScrollView class]]); } From e3c5b4c4a9ef31abe0fe0728209d9feb8e45392c Mon Sep 17 00:00:00 2001 From: Jonas Gessner Date: Wed, 5 Feb 2014 21:49:58 +0100 Subject: [PATCH 2/4] Updated Examples --- .../Classes/BasicDemo/BasicDemoViewController.m | 2 +- .../Classes/CustomLinksDemo/CustomLinksViewController.m | 2 +- .../Classes/TableViewDemo/TableViewDemoViewController.m | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/AttributedLabel Example/Classes/BasicDemo/BasicDemoViewController.m b/AttributedLabel Example/Classes/BasicDemo/BasicDemoViewController.m index 87b948d..a1b5cca 100644 --- a/AttributedLabel Example/Classes/BasicDemo/BasicDemoViewController.m +++ b/AttributedLabel Example/Classes/BasicDemo/BasicDemoViewController.m @@ -176,7 +176,7 @@ -(UIColor*)attributedLabel:(OHAttributedLabel*)attrLabel colorForLink:(NSTextChe } - (void)attributedLabel:(OHAttributedLabel *)attributedLabel longPressedLink:(NSTextCheckingResult *)linkInfo { - NSLog(@"Long Pressed URL %@", linkInfo.URL); + NSLog(@"Long Pressed Link %@", linkInfo); } -(BOOL)attributedLabel:(OHAttributedLabel *)attributedLabel shouldFollowLink:(NSTextCheckingResult *)linkInfo diff --git a/AttributedLabel Example/Classes/CustomLinksDemo/CustomLinksViewController.m b/AttributedLabel Example/Classes/CustomLinksDemo/CustomLinksViewController.m index e0c4230..ddebe67 100644 --- a/AttributedLabel Example/Classes/CustomLinksDemo/CustomLinksViewController.m +++ b/AttributedLabel Example/Classes/CustomLinksDemo/CustomLinksViewController.m @@ -179,7 +179,7 @@ -(IBAction)changeLineSpacing:(UISlider*)slider ///////////////////////////////////////////////////////////////////////////// - (void)attributedLabel:(OHAttributedLabel *)attributedLabel longPressedLink:(NSTextCheckingResult *)linkInfo { - NSLog(@"Long Pressed URL %@", linkInfo.URL); + NSLog(@"Long Pressed Link %@", linkInfo); } -(BOOL)attributedLabel:(OHAttributedLabel *)attributedLabel shouldFollowLink:(NSTextCheckingResult *)linkInfo diff --git a/AttributedLabel Example/Classes/TableViewDemo/TableViewDemoViewController.m b/AttributedLabel Example/Classes/TableViewDemo/TableViewDemoViewController.m index 322d28a..ee4827c 100644 --- a/AttributedLabel Example/Classes/TableViewDemo/TableViewDemoViewController.m +++ b/AttributedLabel Example/Classes/TableViewDemo/TableViewDemoViewController.m @@ -142,7 +142,7 @@ -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath * ///////////////////////////////////////////////////////////////////////////// - (void)attributedLabel:(OHAttributedLabel *)attributedLabel longPressedLink:(NSTextCheckingResult *)linkInfo { - NSLog(@"Long Pressed URL %@", linkInfo.URL); + NSLog(@"Long Pressed Link %@", linkInfo); } -(BOOL)attributedLabel:(OHAttributedLabel *)attributedLabel shouldFollowLink:(NSTextCheckingResult *)linkInfo From e2e0c1f50954bb5449c3f09fc596286837207b77 Mon Sep 17 00:00:00 2001 From: Jonas Gessner Date: Tue, 11 Feb 2014 22:46:11 +0100 Subject: [PATCH 3/4] Removed redundant code --- OHAttributedLabel/Source/OHAttributedLabel.m | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/OHAttributedLabel/Source/OHAttributedLabel.m b/OHAttributedLabel/Source/OHAttributedLabel.m index 76c37f9..ee65ebe 100755 --- a/OHAttributedLabel/Source/OHAttributedLabel.m +++ b/OHAttributedLabel/Source/OHAttributedLabel.m @@ -456,14 +456,10 @@ - (void)longPress:(UILongPressGestureRecognizer *)gesture { BOOL closeToStart = (fabs(_touchStartPoint.x - pt.x) < 10 && fabs(_touchStartPoint.y - pt.y) < 10); // we must check on equality of the ranges themselves since the data detectors create new results - if (_activeLink && (NSEqualRanges(_activeLink.range,linkAtTouchesEnded.range) || closeToStart)) - { + if (_activeLink && (NSEqualRanges(_activeLink.range,linkAtTouchesEnded.range) || closeToStart)) { // Same link on touchEnded than the one on touchBegan, so trigger it [self processLongPressActiveLink]; } - - gesture.enabled = NO; - gesture.enabled = YES; } } From d3efee91fe8bddc1309290bd03931df06ae6bc88 Mon Sep 17 00:00:00 2001 From: Jonas Gessner Date: Wed, 12 Feb 2014 22:06:47 +0100 Subject: [PATCH 4/4] Fixed memory leak --- .../Source/NSAttributedString+Attributes.m | 47 +++++++++++-------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/OHAttributedLabel/Source/NSAttributedString+Attributes.m b/OHAttributedLabel/Source/NSAttributedString+Attributes.m index e64f962..6f0be76 100644 --- a/OHAttributedLabel/Source/NSAttributedString+Attributes.m +++ b/OHAttributedLabel/Source/NSAttributedString+Attributes.m @@ -73,7 +73,7 @@ -(CGSize)sizeConstrainedToSize:(CGSize)maxSize fitRange:(NSRange*)fitRange sz = CTFramesetterSuggestFrameSizeWithConstraints(framesetter,CFRangeMake(0,0),NULL,maxSize,&fitCFRange); sz = CGSizeMake( floorf(sz.width+1) , floorf(sz.height+1) ); // take 1pt of margin for security CFRelease(framesetter); - + if (fitRange) { *fitRange = NSMakeRange((NSUInteger)fitCFRange.location, (NSUInteger)fitCFRange.length); @@ -194,7 +194,7 @@ -(void)setFontFamily:(NSString*)fontFamily size:(CGFloat)size bold:(BOOL)isBold CTFontRef aFont = CTFontCreateWithFontDescriptor(desc, size, NULL); CFRelease(desc); if (!aFont) return; - + [self removeAttribute:(__bridge NSString*)kCTFontAttributeName range:range]; // Work around for Apple leak [self addAttribute:(__bridge NSString*)kCTFontAttributeName value:(__bridge id)aFont range:range]; CFRelease(aFont); @@ -236,11 +236,15 @@ -(void)changeFontWithTraits:(CTFontSymbolicTraits)traits [self beginEditing]; do { // Get font at startPoint + BOOL hadCurrentFont = YES; + CTFontRef currentFont = (__bridge CTFontRef)[self attribute:(__bridge NSString*)kCTFontAttributeName atIndex:startPoint effectiveRange:&effectiveRange]; - if (!currentFont) - { + + if (!currentFont) { + hadCurrentFont = NO; currentFont = CTFontCreateUIFontForLanguage(kCTFontLabelFontType, 0.0, NULL); } + // The range for which this font is effective NSRange fontRange = NSIntersectionRange(range, effectiveRange); // Create the font variant for this font according to new traits @@ -272,9 +276,12 @@ -(void)changeFontWithTraits:(CTFontSymbolicTraits)traits if (fontNameRef) CFRelease(fontNameRef); } + if (!hadCurrentFont) { + CFRelease(currentFont); + } + // Apply the new font with new traits - if (newFont) - { + if (newFont) { [self removeAttribute:(__bridge NSString*)kCTFontAttributeName range:fontRange]; // Work around for Apple leak [self addAttribute:(__bridge NSString*)kCTFontAttributeName value:(__bridge id)newFont range:fontRange]; CFRelease(newFont); @@ -296,18 +303,18 @@ -(void)setTextBold:(BOOL)isBold range:(NSRange)range [self changeFontWithTraits:(isBold?kCTFontTraitBold:0) mask:kCTFontTraitBold range:range newFontFinder:^NSString *(NSString *currentFontName) - { - if ([currentFontName isEqualToString:kHelveticaNeueUI_Italic] || [currentFontName isEqualToString:kHelveticaNeueUI_Bold_Italic]) - { - // Italic private font - return isBold ? kHelveticaNeueUI_Bold_Italic : kHelveticaNeueUI_Italic; - } else if ([currentFontName isEqualToString:kHelveticaNeueUI] || [currentFontName isEqualToString:kHelveticaNeueUI_Bold]) { - // Non-Italic private font - return isBold ? kHelveticaNeueUI_Bold : kHelveticaNeueUI; - } else { - return nil; - } - }]; + { + if ([currentFontName isEqualToString:kHelveticaNeueUI_Italic] || [currentFontName isEqualToString:kHelveticaNeueUI_Bold_Italic]) + { + // Italic private font + return isBold ? kHelveticaNeueUI_Bold_Italic : kHelveticaNeueUI_Italic; + } else if ([currentFontName isEqualToString:kHelveticaNeueUI] || [currentFontName isEqualToString:kHelveticaNeueUI_Bold]) { + // Non-Italic private font + return isBold ? kHelveticaNeueUI_Bold : kHelveticaNeueUI; + } else { + return nil; + } + }]; } -(void)setTextItalics:(BOOL)isItalics range:(NSRange)range @@ -366,9 +373,9 @@ -(void)modifyParagraphStylesInRange:(NSRange)range withBlock:(void(^)(OHParagrap while (NSLocationInRange(loc, range)) { CTParagraphStyleRef currentCTStyle = (__bridge CTParagraphStyleRef)[self attribute:(__bridge NSString*)kCTParagraphStyleAttributeName - atIndex:loc longestEffectiveRange:rangePtr inRange:range]; + atIndex:loc longestEffectiveRange:rangePtr inRange:range]; __block OHParagraphStyle* paraStyle = [OHParagraphStyle paragraphStyleWithCTParagraphStyle:currentCTStyle]; - block(paraStyle); + block(paraStyle); [self setParagraphStyle:paraStyle range:*rangePtr]; loc = NSMaxRange(*rangePtr);