mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 22:25:57 +00:00
[ASTextKitFontSizeAdjuster] Use the constrainedSize’s height to adjust font scaling (#2309)
* refactor shrinking logic # Conflicts: # AsyncDisplayKit/TextKit/ASTextKitFontSizeAdjuster.mm * fix ASTraitCollection sample * updated comments. * fix build errors * adlai’s comments
This commit is contained in:
@@ -16,6 +16,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
@abstract An array of descending scale factors that will be applied to this text node to try to make it fit within its constrained size
|
||||
@discussion This array should be in descending order and NOT contain the scale factor 1.0. For example, it could return @[@(.9), @(.85), @(.8)];
|
||||
@default nil (no scaling)
|
||||
*/
|
||||
@property (nullable, nonatomic, copy) NSArray<NSNumber *> *pointSizeScaleFactors;
|
||||
|
||||
@@ -45,6 +45,8 @@
|
||||
|
||||
+ (void)adjustFontSizeForAttributeString:(NSMutableAttributedString *)attrString withScaleFactor:(CGFloat)scaleFactor
|
||||
{
|
||||
if (scaleFactor == 1.0) return;
|
||||
|
||||
[attrString beginEditing];
|
||||
|
||||
// scale all the attributes that will change the bounding box
|
||||
@@ -133,7 +135,10 @@
|
||||
|
||||
__block CGFloat adjustedScale = 1.0;
|
||||
|
||||
NSArray *scaleFactors = _attributes.pointSizeScaleFactors;
|
||||
// We add the scale factor of 1 to our scaleFactors array so that in the first iteration of the loop below, we are
|
||||
// actually determining if we need to scale at all. If something doesn't fit, we will continue to iterate our scale factors.
|
||||
NSArray *scaleFactors = [@[@(1)] arrayByAddingObjectsFromArray:_attributes.pointSizeScaleFactors];
|
||||
|
||||
[_context performBlockWithLockedTextKitComponents:^(NSLayoutManager *layoutManager, NSTextStorage *textStorage, NSTextContainer *textContainer) {
|
||||
|
||||
// Check for two different situations (and correct for both)
|
||||
@@ -149,53 +154,50 @@
|
||||
}
|
||||
}
|
||||
|
||||
NSUInteger scaleIndex = 0;
|
||||
|
||||
// find the longest word and make sure it fits in the constrained width
|
||||
if ([longestWordNeedingResize length] > 0) {
|
||||
// check to see if we may need to shrink for any of these things
|
||||
BOOL longestWordFits = [longestWordNeedingResize length] ? NO : YES;
|
||||
BOOL maxLinesFits = _attributes.maximumNumberOfLines > 0 ? NO : YES;
|
||||
BOOL heightFits = isinf(_constrainedSize.height) ? YES : NO;
|
||||
|
||||
CGSize longestWordSize = CGSizeZero;
|
||||
if (longestWordFits == NO) {
|
||||
NSRange longestWordRange = [str rangeOfString:longestWordNeedingResize];
|
||||
NSMutableAttributedString *attrString = [textStorage attributedSubstringFromRange:longestWordRange].mutableCopy;
|
||||
CGSize longestWordSize = [attrString boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin context:nil].size;
|
||||
NSAttributedString *attrString = [textStorage attributedSubstringFromRange:longestWordRange];
|
||||
longestWordSize = [attrString boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin context:nil].size;
|
||||
}
|
||||
|
||||
// check if the longest word is larger than our constrained width
|
||||
if (longestWordSize.width > _constrainedSize.width) {
|
||||
|
||||
// we have a word that is too long. Loop through our scale factors until we fit
|
||||
for (NSNumber *scaleFactor in scaleFactors) {
|
||||
// even if we still don't fit, save this scaleFactor so more of the word will fit
|
||||
adjustedScale = [scaleFactor floatValue];
|
||||
|
||||
// adjust here so we start at the proper place in our scale array if we have too many lines
|
||||
scaleIndex++;
|
||||
|
||||
if (std::ceil(longestWordSize.width * [scaleFactor floatValue]) <= _constrainedSize.width) {
|
||||
// we fit! we are done
|
||||
// we may need to shrink for some reason, so let's iterate through our scale factors to see if we actually need to shrink
|
||||
// Note: the first scale factor in the array is 1.0 so will make sure that things don't fit without shrinking
|
||||
for (NSNumber *adjustedScaleObj in scaleFactors) {
|
||||
if (longestWordFits && maxLinesFits && heightFits) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
adjustedScale = [adjustedScaleObj floatValue];
|
||||
|
||||
if (longestWordFits == NO) {
|
||||
// we need to check the longest word to make sure it fits
|
||||
longestWordFits = std::ceil((longestWordSize.width * adjustedScale) <= _constrainedSize.width);
|
||||
}
|
||||
|
||||
if (_attributes.maximumNumberOfLines > 0) {
|
||||
// get the number of lines in our possibly scaled string
|
||||
NSUInteger numberOfLines = [self lineCountForString:textStorage];
|
||||
if (numberOfLines > _attributes.maximumNumberOfLines) {
|
||||
// if the longest word fits, go ahead and check max line and height. If it didn't fit continue to the next scale factor
|
||||
if (longestWordFits == YES) {
|
||||
|
||||
for (NSUInteger index = scaleIndex; index < scaleFactors.count; index++) {
|
||||
NSMutableAttributedString *entireAttributedString = [[NSMutableAttributedString alloc] initWithAttributedString:textStorage];
|
||||
[[self class] adjustFontSizeForAttributeString:entireAttributedString withScaleFactor:[scaleFactors[index] floatValue]];
|
||||
// scale our string by the current scale factor
|
||||
NSMutableAttributedString *scaledString = [[NSMutableAttributedString alloc] initWithAttributedString:textStorage];
|
||||
[[self class] adjustFontSizeForAttributeString:scaledString withScaleFactor:adjustedScale];
|
||||
|
||||
|
||||
// save away this scale factor. Even if we don't fit completely we should still scale down
|
||||
adjustedScale = [scaleFactors[index] floatValue];
|
||||
|
||||
if ([self lineCountForString:entireAttributedString] <= _attributes.maximumNumberOfLines) {
|
||||
// we fit! we are done
|
||||
break;
|
||||
}
|
||||
// check to see if this scaled string fit in the max lines
|
||||
if (maxLinesFits == NO) {
|
||||
maxLinesFits = ([self lineCountForString:scaledString] <= _attributes.maximumNumberOfLines);
|
||||
}
|
||||
|
||||
// if max lines still doesn't fit, continue without checking that we fit in the constrained height
|
||||
if (maxLinesFits == YES && heightFits == NO) {
|
||||
// max lines fit so make sure that we fit in the constrained height.
|
||||
CGSize stringSize = [scaledString boundingRectWithSize:CGSizeMake(_constrainedSize.width, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin context:nil].size;
|
||||
heightFits = (stringSize.height <= _constrainedSize.height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ static const CGFloat kInnerPadding = 10.0f;
|
||||
// kitten image, with a solid background colour serving as placeholder
|
||||
_imageNode = [[ASNetworkImageNode alloc] init];
|
||||
_imageNode.backgroundColor = ASDisplayNodeDefaultPlaceholderColor();
|
||||
_imageNode.size = ASRelativeSizeRangeMakeWithExactCGSize(_kittenSize);
|
||||
_imageNode.style.size = (ASLayoutableSize){ .width = ASDimensionMake(_kittenSize.width), .height = ASDimensionMake(_kittenSize.height) };
|
||||
[_imageNode addTarget:self action:@selector(imageTapped:) forControlEvents:ASControlNodeEventTouchUpInside];
|
||||
|
||||
CGFloat scale = [UIScreen mainScreen].scale;
|
||||
@@ -91,8 +91,8 @@ static const CGFloat kInnerPadding = 10.0f;
|
||||
_textNode = [[ASTextNode alloc] init];
|
||||
_textNode.attributedText = [[NSAttributedString alloc] initWithString:[self kittyIpsum]
|
||||
attributes:[self textStyle]];
|
||||
_textNode.flexShrink = YES;
|
||||
_textNode.flexGrow = YES;
|
||||
_textNode.style.flexShrink = YES;
|
||||
_textNode.style.flexGrow = YES;
|
||||
[self addSubnode:_textNode];
|
||||
|
||||
return self;
|
||||
@@ -141,10 +141,10 @@ static const CGFloat kInnerPadding = 10.0f;
|
||||
[stackSpec setChildren:@[_imageNode, _textNode]];
|
||||
|
||||
if (self.asyncTraitCollection.horizontalSizeClass == UIUserInterfaceSizeClassRegular) {
|
||||
_imageNode.alignSelf = ASStackLayoutAlignSelfStart;
|
||||
_imageNode.style.alignSelf = ASStackLayoutAlignSelfStart;
|
||||
stackSpec.direction = ASStackLayoutDirectionHorizontal;
|
||||
} else {
|
||||
_imageNode.alignSelf = ASStackLayoutAlignSelfCenter;
|
||||
_imageNode.style.alignSelf = ASStackLayoutAlignSelfCenter;
|
||||
stackSpec.direction = ASStackLayoutDirectionVertical;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,8 +33,8 @@ static NSString *kLinkAttributeName = @"PlaceKittenNodeLinkAttributeName";
|
||||
return nil;
|
||||
|
||||
_textNode = [[ASTextNode alloc] init];
|
||||
_textNode.flexGrow = YES;
|
||||
_textNode.flexShrink = YES;
|
||||
_textNode.style.flexGrow = YES;
|
||||
_textNode.style.flexShrink = YES;
|
||||
_textNode.maximumNumberOfLines = 3;
|
||||
[self addSubnode:_textNode];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user