From a5c8deb10ee1ba9cb74386e185892ac6d6cb1096 Mon Sep 17 00:00:00 2001 From: Arnold Tang Date: Wed, 15 Nov 2017 23:24:24 +0800 Subject: [PATCH 1/8] Bug fix --- KILabel/Source/KILabel.h | 0 KILabel/Source/KILabel.m | 22 ++++++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) mode change 100644 => 100755 KILabel/Source/KILabel.h mode change 100644 => 100755 KILabel/Source/KILabel.m diff --git a/KILabel/Source/KILabel.h b/KILabel/Source/KILabel.h old mode 100644 new mode 100755 diff --git a/KILabel/Source/KILabel.m b/KILabel/Source/KILabel.m old mode 100644 new mode 100755 index 37dbbff..4a696c6 --- a/KILabel/Source/KILabel.m +++ b/KILabel/Source/KILabel.m @@ -309,12 +309,25 @@ - (void)updateTextStoreWithAttributedString:(NSAttributedString *)attributedStri if (_textStorage) { // Set the string on the storage - [_textStorage setAttributedString:attributedString]; + // setAttributedString: requires a non-null argument + if (attributedString) { + [_textStorage setAttributedString:attributedString]; + } + else { + [_textStorage setAttributedString: [NSAttributedString new]]; + } + } else { // Create a new text storage and attach it correctly to the layout manager - _textStorage = [[NSTextStorage alloc] initWithAttributedString:attributedString]; + // setAttributedString: requires a non-null argument + if (attributedString) { + _textStorage = [[NSTextStorage alloc] initWithAttributedString: attributedString]; + } + else { + _textStorage = [[NSTextStorage alloc] initWithAttributedString: [NSAttributedString new]]; + } [_textStorage addLayoutManager:_layoutManager]; [_layoutManager setTextStorage:_textStorage]; } @@ -607,6 +620,11 @@ - (void)setBounds:(CGRect)bounds [super setBounds:bounds]; _textContainer.size = self.bounds.size; + + if (self.numberOfLines == 0 && bounds.size.width != self.preferredMaxLayoutWidth) { + self.preferredMaxLayoutWidth = self.bounds.size.width; + [self setNeedsUpdateConstraints]; + } } - (void)layoutSubviews From f57ae03b0289b92d6ccc63b6af9760f1904fc64a Mon Sep 17 00:00:00 2001 From: Arnold Tang Date: Wed, 15 Nov 2017 23:26:29 +0800 Subject: [PATCH 2/8] Set height of textRect to 0 for empty string --- KILabel/Source/KILabel.m | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/KILabel/Source/KILabel.m b/KILabel/Source/KILabel.m index 4a696c6..82d5f5e 100755 --- a/KILabel/Source/KILabel.m +++ b/KILabel/Source/KILabel.m @@ -567,6 +567,10 @@ - (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)num CGFloat offsetY = (bounds.size.height - textBounds.size.height) / 2.0; textBounds.origin.y += offsetY; } + + if (_layoutManager.textStorage.length == 0) { + textBounds.size.height = 0.0f; + } // Restore the old container state before we exit under any circumstances _textContainer.size = savedTextContainerSize; From 804e1d6c5e050d49908177ee5961c3b8058c2a8f Mon Sep 17 00:00:00 2001 From: Arnold Tang Date: Thu, 16 Nov 2017 17:03:23 +0800 Subject: [PATCH 3/8] Accept minor movement in touchesMoved --- KILabel/Source/KILabel.m | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/KILabel/Source/KILabel.m b/KILabel/Source/KILabel.m index 82d5f5e..e35c0fe 100755 --- a/KILabel/Source/KILabel.m +++ b/KILabel/Source/KILabel.m @@ -58,6 +58,7 @@ @interface KILabel() @implementation KILabel { NSMutableDictionary *_linkTypeAttributes; + CGPoint touchBeganLocation; } #pragma mark - Construction @@ -658,8 +659,8 @@ - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event // Get the info for the touched link if there is one NSDictionary *touchedLink; - CGPoint touchLocation = [[touches anyObject] locationInView:self]; - touchedLink = [self linkAtPoint:touchLocation]; + touchBeganLocation = [[touches anyObject] locationInView:self]; + touchedLink = [self linkAtPoint:touchBeganLocation]; if (touchedLink) { @@ -675,7 +676,11 @@ - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesMoved:touches withEvent:event]; - _isTouchMoved = YES; + CGPoint touchLocation = [[touches anyObject] locationInView:self]; + if (fabs(touchLocation.x - touchBeganLocation.x) > 1.0f && + fabs(touchLocation.y - touchBeganLocation.y) > 1.0f) { + _isTouchMoved = YES; + } } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event From 95b6175b1d24fa3919c0794df82b09019e91e9fe Mon Sep 17 00:00:00 2001 From: Arnold Tang Date: Sun, 3 Dec 2017 23:15:29 +0800 Subject: [PATCH 4/8] Use custom NSLayoutManager to create rounded corner background called glyphRangeForTextContainer: before calling usedRect as apple document suggested. --- KILabel/Source/KILabel.m | 74 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 2 deletions(-) diff --git a/KILabel/Source/KILabel.m b/KILabel/Source/KILabel.m index e35c0fe..0830fe0 100755 --- a/KILabel/Source/KILabel.m +++ b/KILabel/Source/KILabel.m @@ -29,12 +29,80 @@ NSString * const KILabelRangeKey = @"range"; NSString * const KILabelLinkKey = @"link"; +@interface KILayoutManager : NSLayoutManager +@end +@implementation KILayoutManager +- (void)fillBackgroundRectArray:(const CGRect *)rectArray count:(NSUInteger)rectCount forCharacterRange:(NSRange)charRange color:(UIColor *)color +{ + CGFloat halfLineWidth = 4.; // change this to change corners radius + CGFloat marginX = 1.5f; // change this to adjust x margin + + CGMutablePathRef path = CGPathCreateMutable(); + + CGRect rect0 = rectArray[0]; + rect0.origin.x -= marginX; + rect0.size.width += marginX * 2; + + if (rectCount == 1 || + (rectCount == 2 && (CGRectGetMaxX(rectArray[1]) < CGRectGetMinX(rectArray[0]))) + ) + { + // 1 rect or 2 rects without edges in contact + CGPathAddRect(path, NULL, CGRectInset(rect0, halfLineWidth, halfLineWidth)); + if (rectCount == 2) { + CGRect rect1 = rectArray[1]; + rect1.origin.x -= marginX; + rect1.size.width += marginX * 2; + CGPathAddRect(path, NULL, CGRectInset(rect1, halfLineWidth, halfLineWidth)); + } + } + else + { + // 2 or 3 rects + NSUInteger lastRect = rectCount - 1; + CGRect rectLast = rectArray[lastRect]; + rectLast.origin.x -= marginX / 2; + rectLast.size.width += marginX; + + CGPathMoveToPoint(path, NULL, CGRectGetMinX(rect0) + halfLineWidth, CGRectGetMaxY(rect0) + halfLineWidth); + + CGPathAddLineToPoint(path, NULL, CGRectGetMinX(rect0) + halfLineWidth, CGRectGetMinY(rect0) + halfLineWidth); + CGPathAddLineToPoint(path, NULL, CGRectGetMaxX(rect0) - halfLineWidth, CGRectGetMinY(rect0) + halfLineWidth); + + CGPathAddLineToPoint(path, NULL, CGRectGetMaxX(rect0) - halfLineWidth, CGRectGetMinY(rectLast) - halfLineWidth); + CGPathAddLineToPoint(path, NULL, CGRectGetMaxX(rectLast) - halfLineWidth, CGRectGetMinY(rectLast) - halfLineWidth); + + CGPathAddLineToPoint(path, NULL, CGRectGetMaxX(rectLast) - halfLineWidth, CGRectGetMaxY(rectLast) - halfLineWidth); + CGPathAddLineToPoint(path, NULL, CGRectGetMinX(rectLast) + halfLineWidth, CGRectGetMaxY(rectLast) - halfLineWidth); + + CGPathAddLineToPoint(path, NULL, CGRectGetMinX(rectLast) + halfLineWidth, CGRectGetMaxY(rect0) + halfLineWidth); + + CGPathCloseSubpath(path); + } + + [color set]; // set fill and stroke color + + CGContextRef ctx = UIGraphicsGetCurrentContext(); + CGContextSetLineWidth(ctx, halfLineWidth * 2.); + CGContextSetLineJoin(ctx, kCGLineJoinRound); + + CGContextSetAllowsAntialiasing(ctx, YES); + CGContextSetShouldAntialias(ctx, YES); + + CGContextAddPath(ctx, path); + CGPathRelease(path); + + CGContextDrawPath(ctx, kCGPathFillStroke); +} + +@end + #pragma mark - Private Interface @interface KILabel() // Used to control layout of glyphs and rendering -@property (nonatomic, retain) NSLayoutManager *layoutManager; +@property (nonatomic, retain) KILayoutManager *layoutManager; // Specifies the space in which to render text @property (nonatomic, retain) NSTextContainer *textContainer; @@ -96,7 +164,7 @@ - (void)setupTextSystem _textContainer.size = self.frame.size; // Create a layout manager for rendering - _layoutManager = [[NSLayoutManager alloc] init]; + _layoutManager = [[KILayoutManager alloc] init]; _layoutManager.delegate = self; [_layoutManager addTextContainer:_textContainer]; @@ -555,6 +623,7 @@ - (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)num _textContainer.maximumNumberOfLines = numberOfLines; // Measure the text with the new state + [_layoutManager glyphRangeForTextContainer:_textContainer]; // Force layout text as suggested by Apple document CGRect textBounds = [_layoutManager usedRectForTextContainer:_textContainer]; // Position the bounds and round up the size for good measure @@ -600,6 +669,7 @@ - (CGPoint)calcGlyphsPositionInView { CGPoint textOffset = CGPointZero; + [_layoutManager glyphRangeForTextContainer:_textContainer]; // Force layout text as suggested by Apple document CGRect textBounds = [_layoutManager usedRectForTextContainer:_textContainer]; textBounds.size.width = ceil(textBounds.size.width); textBounds.size.height = ceil(textBounds.size.height); From af285486154bdffb0d646e6c0f29a3e04323d16a Mon Sep 17 00:00:00 2001 From: Arnold Tang Date: Wed, 13 Dec 2017 00:02:01 +0800 Subject: [PATCH 5/8] remove redundant glyphrangefortextcontainter --- KILabel/Source/KILabel.m | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/KILabel/Source/KILabel.m b/KILabel/Source/KILabel.m index 0830fe0..8ce3afb 100755 --- a/KILabel/Source/KILabel.m +++ b/KILabel/Source/KILabel.m @@ -656,7 +656,7 @@ - (void)drawTextInRect:(CGRect)rect // [super drawTextInRect:rect]; // Calculate the offset of the text in the view - NSRange glyphRange = [_layoutManager glyphRangeForTextContainer:_textContainer]; + NSRange glyphRange = [_layoutManager glyphRangeForTextContainer:_textContainer]; // Force layout text as suggested by Apple document CGPoint glyphsPosition = [self calcGlyphsPositionInView]; // Drawing code @@ -669,7 +669,6 @@ - (CGPoint)calcGlyphsPositionInView { CGPoint textOffset = CGPointZero; - [_layoutManager glyphRangeForTextContainer:_textContainer]; // Force layout text as suggested by Apple document CGRect textBounds = [_layoutManager usedRectForTextContainer:_textContainer]; textBounds.size.width = ceil(textBounds.size.width); textBounds.size.height = ceil(textBounds.size.height); From e878d37e6abd44ab2e8bbbaeeb89cc926a480a43 Mon Sep 17 00:00:00 2001 From: Arnold Tang Date: Thu, 22 Feb 2018 23:49:53 +0800 Subject: [PATCH 6/8] Fix repeated notification issue Ffix NSInteger conversion Hide text of blocked article --- KILabel/Source/KILabel.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/KILabel/Source/KILabel.m b/KILabel/Source/KILabel.m index 8ce3afb..8c4135b 100755 --- a/KILabel/Source/KILabel.m +++ b/KILabel/Source/KILabel.m @@ -777,10 +777,10 @@ - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event [self receivedActionForLinkType:linkType string:touchedSubstring range:range]; } - else - { - [super touchesBegan:touches withEvent:event]; - } +// else +// { +// [super touchesBegan:touches withEvent:event]; +// } self.selectedRange = NSMakeRange(0, 0); } From d3f6b9490404043d4e20853b72ed3e1505470aad Mon Sep 17 00:00:00 2001 From: Arnold Tang Date: Sun, 5 Aug 2018 23:59:39 +0800 Subject: [PATCH 7/8] invalidate intrinsic content size when setting text in KILabel. Fix layout issue in iOS 12 --- KILabel/Source/KILabel.m | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/KILabel/Source/KILabel.m b/KILabel/Source/KILabel.m index 8c4135b..296b087 100755 --- a/KILabel/Source/KILabel.m +++ b/KILabel/Source/KILabel.m @@ -289,7 +289,9 @@ - (void)setText:(NSString *)text { text = @""; } - + if (@available(iOS 12.0, *)) { + [self invalidateIntrinsicContentSize]; + } NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:text attributes:[self attributesFromProperties]]; [self updateTextStoreWithAttributedString:attributedText]; } @@ -298,7 +300,9 @@ - (void)setAttributedText:(NSAttributedString *)attributedText { // Pass the text to the super class first [super setAttributedText:attributedText]; - + if (@available(iOS 12.0, *)) { + [self invalidateIntrinsicContentSize]; + } [self updateTextStoreWithAttributedString:attributedText]; } From e9c081635109c62eae5860dabe50b7f540520661 Mon Sep 17 00:00:00 2001 From: Arnold Tang Date: Sun, 17 May 2026 17:45:15 +0100 Subject: [PATCH 8/8] check if perform action --- KILabel/Source/KILabel.m | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/KILabel/Source/KILabel.m b/KILabel/Source/KILabel.m index 296b087..b840f28 100755 --- a/KILabel/Source/KILabel.m +++ b/KILabel/Source/KILabel.m @@ -864,4 +864,21 @@ + (NSAttributedString *)sanitizeAttributedString:(NSAttributedString *)attribute return restyled; } +#pragma mark - Menu items + +- (BOOL)canPerformAction:(SEL)action withSender:(id)sender { + if (action == @selector(printToConsole) || action == @selector(copy:)) { + return YES; + } + else { + return NO; + } +} + +- (void)printToConsole { + +} + + + @end