Skip to content

Commit

Permalink
More efficient solution to line truncation in DTAttributedLabel.
Browse files Browse the repository at this point in the history
Bug fixes in DTCoreTextLayoutFrame :
- paragraphRanges was not properly calculated when a string isn't ended with '\n'
- uninitialized variable baseWritingDirection in [DTCoreTextLayoutFrame_buildLinesWithTypesetter] so for a attributed strings without paragraph style (by ex. created with [NSAttributedString initWithString:] ) lines were rendered wrong
  • Loading branch information
shc committed Apr 18, 2013
1 parent 732502a commit 5144588
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 34 deletions.
38 changes: 21 additions & 17 deletions Core/Source/DTAttributedLabel.m
Expand Up @@ -18,17 +18,6 @@ + (Class)layerClass
return [CALayer class];
}

- (DTCoreTextLayoutFrame *)layoutFrame
{
self.layoutFrameHeightIsConstrainedByBounds = YES; // height is not flexible
DTCoreTextLayoutFrame * layoutFrame = [super layoutFrame];
layoutFrame.numberOfLines = self.numberOfLines;
layoutFrame.lineBreakMode = self.lineBreakMode;
layoutFrame.truncationString = self.truncationString;
layoutFrame.noLeadingOnFirstLine = YES;
return layoutFrame;
}

- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
Expand All @@ -37,6 +26,9 @@ - (id)initWithFrame:(CGRect)frame
{
// we want to relayout the text if height or width change
self.relayoutMask = DTAttributedTextContentViewRelayoutOnHeightChanged | DTAttributedTextContentViewRelayoutOnWidthChanged;

self.layoutFrameHeightIsConstrainedByBounds = YES; // height is not flexible
self.shouldAddFirstLineLeading = NO;
}

return self;
Expand All @@ -57,6 +49,11 @@ - (CGSize)intrinsicContentSize

#pragma mark - Properties

- (NSInteger)numberOfLines
{
return _numberOfLines;
}

- (void)setNumberOfLines:(NSInteger)numberOfLines
{
if (numberOfLines != _numberOfLines)
Expand All @@ -66,6 +63,11 @@ - (void)setNumberOfLines:(NSInteger)numberOfLines
}
}

- (NSLineBreakMode)lineBreakMode
{
return _lineBreakMode;
}

- (void)setLineBreakMode:(NSLineBreakMode)lineBreakMode
{
if (lineBreakMode != _lineBreakMode)
Expand All @@ -75,17 +77,19 @@ - (void)setLineBreakMode:(NSLineBreakMode)lineBreakMode
}
}

- (void)setTruncationString:(NSAttributedString *)trunctionString
- (NSAttributedString*)truncationString
{
return _truncationString;
}

- (void)setTruncationString:(NSAttributedString *)truncationString
{
if (trunctionString != _truncationString)
if (![truncationString isEqualToAttributedString:_truncationString])
{
_truncationString = trunctionString;
_truncationString = truncationString;
[self relayoutText];
}
}

@synthesize numberOfLines = _numberOfLines;
@synthesize lineBreakMode = _lineBreakMode;
@synthesize truncationString = _truncationString;

@end
5 changes: 5 additions & 0 deletions Core/Source/DTAttributedTextContentView.h
Expand Up @@ -129,6 +129,11 @@ typedef NSUInteger DTAttributedTextContentViewRelayoutMask;
NSMutableDictionary *customViewsForAttachmentsIndex;

BOOL _flexibleHeight;

// for layoutFrame
NSInteger _numberOfLines;
NSLineBreakMode _lineBreakMode;
NSAttributedString *_truncationString;
}


Expand Down
8 changes: 8 additions & 0 deletions Core/Source/DTAttributedTextContentView.m
Expand Up @@ -574,6 +574,11 @@ - (CGSize)suggestedFrameSizeToFitEntireStringConstraintedToWidth:(CGFloat)width
CGRect rect = [self _frameForLayoutFrameConstraintedToWidth:width];
DTCoreTextLayoutFrame *tmpLayoutFrame = [self.layouter layoutFrameWithRect:rect range:NSMakeRange(0, 0)];

// assign current layout frame properties to tmpLayoutFrame
tmpLayoutFrame.numberOfLines = _numberOfLines;
tmpLayoutFrame.lineBreakMode = _lineBreakMode;
tmpLayoutFrame.truncationString = _truncationString;

// we have a layout frame and from this we get the needed size
return CGSizeMake(tmpLayoutFrame.frame.size.width + _edgeInsets.left + _edgeInsets.right, CGRectGetMaxY(tmpLayoutFrame.frame) + _edgeInsets.bottom);
}
Expand Down Expand Up @@ -772,6 +777,9 @@ - (DTCoreTextLayoutFrame *)layoutFrame

_layoutFrame = [theLayouter layoutFrameWithRect:rect range:NSMakeRange(0, 0)];
_layoutFrame.noLeadingOnFirstLine = !_shouldAddFirstLineLeading;
_layoutFrame.numberOfLines = _numberOfLines;
_layoutFrame.lineBreakMode = _lineBreakMode;
_layoutFrame.truncationString = _truncationString;

// this must have been the initial layout pass
CGSize neededSize = CGSizeMake(_layoutFrame.frame.size.width + _edgeInsets.left + _edgeInsets.right, CGRectGetMaxY(_layoutFrame.frame) + _edgeInsets.bottom);
Expand Down
49 changes: 32 additions & 17 deletions Core/Source/DTCoreTextLayoutFrame.m
Expand Up @@ -419,6 +419,8 @@ - (void)_buildLinesWithTypesetter
if (CTParagraphStyleGetValueForSpecifier(paragraphStyle, kCTParagraphStyleSpecifierBaseWritingDirection, sizeof(baseWritingDirection), &baseWritingDirection))
{
isRTL = (baseWritingDirection == kCTWritingDirectionRightToLeft);
} else {
baseWritingDirection = kCTWritingDirectionNatural;
}

switch (textAlignment)
Expand Down Expand Up @@ -1698,27 +1700,40 @@ - (NSArray *)paragraphRanges
{
NSString *plainString = [[self attributedStringFragment] string];

NSInteger stringLength = [plainString length];
NSArray *paragraphs = [plainString componentsSeparatedByString:@"\n"];
NSRange range = NSMakeRange(0, 0);
NSMutableArray *tmpArray = [NSMutableArray array];

for (NSString *oneString in paragraphs)
{
range.length = [oneString length]+1;
if( [paragraphs count] == 1 ) {

NSValue *value = [NSValue valueWithRange:range];
[tmpArray addObject:value];
_paragraphRanges = [NSArray arrayWithObject:[NSValue valueWithRange:NSMakeRange(0, stringLength)]];

range.location += range.length;
}
} else {

// prevent counting a paragraph after a final newline
if ([plainString hasSuffix:@"\n"])
{
[tmpArray removeLastObject];
NSRange range = NSMakeRange(0, 0);

NSMutableArray *tmpArray = [NSMutableArray array];

for (NSString *oneString in paragraphs)
{
range.length = [oneString length];
if( NSMaxRange(range) < stringLength ) {
// add new line character to range
range.location += 1;
}

NSValue *value = [NSValue valueWithRange:range];
[tmpArray addObject:value];

range.location += range.length;
}

// prevent counting a paragraph after a final newline
if ([plainString hasSuffix:@"\n"])
{
[tmpArray removeLastObject];
}

_paragraphRanges = [tmpArray copy];
}

_paragraphRanges = [tmpArray copy];
}

return _paragraphRanges;
Expand All @@ -1727,7 +1742,7 @@ - (NSArray *)paragraphRanges
- (void)setNumberOfLines:(NSInteger)numberOfLines
{
if( _numberOfLines != numberOfLines ) {
_numberOfLines = numberOfLines;
_numberOfLines = numberOfLines;
// clear lines cache
_lines = nil;
}
Expand Down

0 comments on commit 5144588

Please sign in to comment.