Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file modified KILabel/Source/KILabel.h
100644 → 100755
Empty file.
145 changes: 131 additions & 14 deletions KILabel/Source/KILabel.m
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -58,6 +126,7 @@ @interface KILabel()
@implementation KILabel
{
NSMutableDictionary *_linkTypeAttributes;
CGPoint touchBeganLocation;
}

#pragma mark - Construction
Expand Down Expand Up @@ -95,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];

Expand Down Expand Up @@ -220,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];
}
Expand All @@ -229,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];
}

Expand Down Expand Up @@ -309,12 +382,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];
}
Expand Down Expand Up @@ -541,6 +627,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
Expand All @@ -554,6 +641,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;
Expand All @@ -569,7 +660,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
Expand Down Expand Up @@ -607,6 +698,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
Expand Down Expand Up @@ -636,8 +732,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)
{
Expand All @@ -653,7 +749,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
Expand Down Expand Up @@ -681,10 +781,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);
}
Expand Down Expand Up @@ -764,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