add ASTextKitFontSizeAdjuster

This commit is contained in:
Luke Zhao
2016-01-20 16:28:46 -08:00
parent 882379a820
commit f413a618e0
8 changed files with 175 additions and 2 deletions

View File

@@ -81,6 +81,10 @@ struct ASTextKitAttributes {
The radius that should be applied to the shadow blur. Larger values mean a larger, more blurred shadow.
*/
CGFloat shadowRadius;
/**
The minimum scale that the textnode can apply to fit long words in constrained size.
*/
CGFloat minimumScaleFactor;
/**
A pointer to a function that that returns a custom layout manager subclass. If nil, defaults to NSLayoutManager.
*/
@@ -103,6 +107,7 @@ struct ASTextKitAttributes {
[shadowColor copy],
shadowOpacity,
shadowRadius,
minimumScaleFactor,
layoutManagerFactory
};
};
@@ -114,6 +119,7 @@ struct ASTextKitAttributes {
&& maximumNumberOfLines == other.maximumNumberOfLines
&& shadowOpacity == other.shadowOpacity
&& shadowRadius == other.shadowRadius
&& minimumScaleFactor == other.minimumScaleFactor
&& layoutManagerFactory == other.layoutManagerFactory
&& CGSizeEqualToSize(shadowOffset, other.shadowOffset)
&& _objectsEqual(exclusionPaths, other.exclusionPaths)

View File

@@ -0,0 +1,19 @@
//
// ASTextKitFontSizeAdjuster.h
// AsyncDisplayKit
//
// Created by Luke on 1/20/16.
// Copyright © 2016 Facebook. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface ASTextKitFontSizeAdjuster : NSObject
- (instancetype)initWithContext:(ASTextKitContext *)context
minimumScaleFactor:(CGFloat)minimumScaleFactor
constrainedSize:(CGSize)constrainedSize;
- (void) adjustFontSize;
@end

View File

@@ -0,0 +1,100 @@
//
// ASTextKitFontSizeAdjuster.m
// AsyncDisplayKit
//
// Created by Luke on 1/20/16.
// Copyright © 2016 Facebook. All rights reserved.
//
#import "ASTextKitContext.h"
#import "ASTextKitFontSizeAdjuster.h"
@implementation ASTextKitFontSizeAdjuster
{
__weak ASTextKitContext *_context;
CGFloat _minimumScaleFactor;
CGSize _constrainedSize;
}
- (instancetype)initWithContext:(ASTextKitContext *)context
minimumScaleFactor:(CGFloat)minimumScaleFactor
constrainedSize:(CGSize)constrainedSize
{
if (self = [super init]) {
_context = context;
_minimumScaleFactor = minimumScaleFactor;
_constrainedSize = constrainedSize;
}
return self;
}
- (CGSize)sizeForAttributedString:(NSAttributedString *)attrString
{
return [attrString boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)
options:NSStringDrawingUsesLineFragmentOrigin
context:nil].size;
}
- (void) adjustFontSizeForAttributeString:(NSMutableAttributedString *)attrString withScaleFactor:(CGFloat)scaleFactor
{
{
[attrString beginEditing];
[attrString enumerateAttribute:NSFontAttributeName inRange:NSMakeRange(0, attrString.length) options:0 usingBlock:^(id value, NSRange range, BOOL *stop) {
UIFont* font = value;
font = [font fontWithSize:font.pointSize * scaleFactor];
[attrString removeAttribute:NSFontAttributeName range:range];
[attrString addAttribute:NSFontAttributeName value:font range:range];
}];
[attrString endEditing];
}
}
- (void)adjustFontSize
{
if (_minimumScaleFactor <= 0 || _minimumScaleFactor >= 1) {
return;
}
[_context performBlockWithLockedTextKitComponents:^(NSLayoutManager *layoutManager, NSTextStorage *textStorage, NSTextContainer *textContainer) {
NSString *str = textStorage.string;
NSArray *words = [str componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSString *longestWordNeedingResize = @"";
for (NSString *word in words) {
if ([word length] > [longestWordNeedingResize length]) {
longestWordNeedingResize = word;
}
}
if ([longestWordNeedingResize length] == 0) {
return;
}
NSRange range = [str rangeOfString:longestWordNeedingResize];
NSMutableAttributedString *attrString = [textStorage attributedSubstringFromRange:range].mutableCopy;
CGSize defaultSize = [self sizeForAttributedString:attrString];
if (defaultSize.width > _constrainedSize.width) {
[attrString removeAttribute:NSParagraphStyleAttributeName range:NSMakeRange(0, [attrString length])];
NSStringDrawingContext *context = [[NSStringDrawingContext alloc] init];
context.minimumScaleFactor = _minimumScaleFactor;
[attrString boundingRectWithSize:CGSizeMake(_constrainedSize.width, defaultSize.height)
options:NSStringDrawingUsesLineFragmentOrigin
context:context];
[self adjustFontSizeForAttributeString:attrString withScaleFactor:context.actualScaleFactor];
if ([self sizeForAttributedString:attrString].width <= _constrainedSize.width) {
[self adjustFontSizeForAttributeString:textStorage withScaleFactor:context.actualScaleFactor];
NSLog(@"ASTextKitFontSizeAdjuster : adjusted \"%@\"to fontsize actualScaleFactor:%f", longestWordNeedingResize, context.actualScaleFactor);
}
}
}];
}
@end

View File

@@ -16,6 +16,7 @@
@class ASTextKitContext;
@class ASTextKitShadower;
@class ASTextKitFontSizeAdjuster;
@protocol ASTextKitTruncating;
/**
@@ -47,6 +48,8 @@ dvlkferufedgjnhjjfhldjedlunvtdtv
@property (nonatomic, strong, readonly) id<ASTextKitTruncating> truncater;
@property (nonatomic, strong, readonly) ASTextKitFontSizeAdjuster *fontSizeAdjuster;
@property (nonatomic, strong, readonly) ASTextKitShadower *shadower;
@property (nonatomic, assign, readonly) ASTextKitAttributes attributes;

View File

@@ -15,6 +15,7 @@
#import "ASTextKitContext.h"
#import "ASTextKitShadower.h"
#import "ASTextKitTailTruncater.h"
#import "ASTextKitFontSizeAdjuster.h"
#import "ASTextKitTruncating.h"
static NSCharacterSet *_defaultAvoidTruncationCharacterSet()
@@ -34,7 +35,7 @@ static NSCharacterSet *_defaultAvoidTruncationCharacterSet()
CGSize _calculatedSize;
BOOL _sizeIsCalculated;
}
@synthesize attributes = _attributes, context = _context, shadower = _shadower, truncater = _truncater;
@synthesize attributes = _attributes, context = _context, shadower = _shadower, truncater = _truncater, fontSizeAdjuster = _fontSizeAdjuster;
#pragma mark - Initialization
@@ -75,6 +76,19 @@ static NSCharacterSet *_defaultAvoidTruncationCharacterSet()
return _truncater;
}
- (ASTextKitFontSizeAdjuster *)fontSizeAdjuster
{
if (!_fontSizeAdjuster) {
ASTextKitAttributes attributes = _attributes;
// We must inset the constrained size by the size of the shadower.
CGSize shadowConstrainedSize = [[self shadower] insetSizeWithConstrainedSize:_constrainedSize];
_fontSizeAdjuster = [[ASTextKitFontSizeAdjuster alloc] initWithContext:[self context]
minimumScaleFactor:attributes.minimumScaleFactor
constrainedSize:shadowConstrainedSize];
}
return _fontSizeAdjuster;
}
- (ASTextKitContext *)context
{
if (!_context) {
@@ -94,13 +108,16 @@ static NSCharacterSet *_defaultAvoidTruncationCharacterSet()
- (void)_calculateSize
{
if (_attributes.minimumScaleFactor < 1 && _attributes.minimumScaleFactor > 0) {
[[self fontSizeAdjuster] adjustFontSize];
}
// Force glyph generation and layout, which may not have happened yet (and isn't triggered by
// -usedRectForTextContainer:).
[[self context] performBlockWithLockedTextKitComponents:^(NSLayoutManager *layoutManager, NSTextStorage *textStorage, NSTextContainer *textContainer) {
[layoutManager ensureLayoutForTextContainer:textContainer];
}];
CGRect constrainedRect = {CGPointZero, _constrainedSize};
__block CGRect boundingRect;
[[self context] performBlockWithLockedTextKitComponents:^(NSLayoutManager *layoutManager, NSTextStorage *textStorage, NSTextContainer *textContainer) {