Use reference cells for measurement.

// FREEBIE
pull/1/head
Matthew Chen 8 years ago
parent de56c77f3f
commit 91af4f93e1

@ -31,8 +31,20 @@ NS_ASSUME_NONNULL_BEGIN
- (CGSize)jsq_avatarSizeForMessageData:(id<JSQMessageData>)messageData - (CGSize)jsq_avatarSizeForMessageData:(id<JSQMessageData>)messageData
withLayout:(JSQMessagesCollectionViewFlowLayout *)layout; withLayout:(JSQMessagesCollectionViewFlowLayout *)layout;
- (CGFloat)textBubbleWidthForLayout:(JSQMessagesCollectionViewFlowLayout *)layout; - (CGFloat)textBubbleWidthForLayout:(JSQMessagesCollectionViewFlowLayout *)layout;
@end
#pragma mark -
@interface OWSMessagesBubblesSizeCalculator ()
@property (nonatomic) OWSSystemMessageCell *referenceSystemMessageCell;
@property (nonatomic) OWSUnreadIndicatorCell *referenceUnreadIndicatorCell;
@end @end
#pragma mark -
@implementation OWSMessagesBubblesSizeCalculator @implementation OWSMessagesBubblesSizeCalculator
/** /**
@ -98,6 +110,7 @@ NS_ASSUME_NONNULL_BEGIN
cacheKey:(id)cacheKey cacheKey:(id)cacheKey
layout:(JSQMessagesCollectionViewFlowLayout *)layout layout:(JSQMessagesCollectionViewFlowLayout *)layout
{ {
OWSAssert([NSThread isMainThread]);
OWSAssert(interaction); OWSAssert(interaction);
OWSAssert(cacheKey); OWSAssert(cacheKey);
@ -106,8 +119,12 @@ NS_ASSUME_NONNULL_BEGIN
return [cachedSize CGSizeValue]; return [cachedSize CGSizeValue];
} }
CGSize result = if (!self.referenceSystemMessageCell) {
[OWSSystemMessageCell cellSizeForInteraction:interaction collectionViewWidth:layout.collectionView.width]; self.referenceSystemMessageCell = [OWSSystemMessageCell new];
}
CGSize result = [self.referenceSystemMessageCell cellSizeForInteraction:interaction
collectionViewWidth:layout.collectionView.width];
[self.cache setObject:[NSValue valueWithCGSize:result] forKey:cacheKey]; [self.cache setObject:[NSValue valueWithCGSize:result] forKey:cacheKey];
@ -126,8 +143,12 @@ NS_ASSUME_NONNULL_BEGIN
return [cachedSize CGSizeValue]; return [cachedSize CGSizeValue];
} }
CGSize result = if (!self.referenceUnreadIndicatorCell) {
[OWSUnreadIndicatorCell cellSizeForInteraction:interaction collectionViewWidth:layout.collectionView.width]; self.referenceUnreadIndicatorCell = [OWSUnreadIndicatorCell new];
}
CGSize result = [self.referenceUnreadIndicatorCell cellSizeForInteraction:interaction
collectionViewWidth:layout.collectionView.width];
[self.cache setObject:[NSValue valueWithCGSize:result] forKey:cacheKey]; [self.cache setObject:[NSValue valueWithCGSize:result] forKey:cacheKey];

@ -25,7 +25,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)configureWithInteraction:(TSInteraction *)interaction; - (void)configureWithInteraction:(TSInteraction *)interaction;
+ (CGSize)cellSizeForInteraction:(TSInteraction *)interaction collectionViewWidth:(CGFloat)collectionViewWidth; - (CGSize)cellSizeForInteraction:(TSInteraction *)interaction collectionViewWidth:(CGFloat)collectionViewWidth;
@end @end

@ -51,7 +51,10 @@ NS_ASSUME_NONNULL_BEGIN
- (void)commontInit - (void)commontInit
{ {
OWSAssert(!self.imageView); if (self.imageView) {
// Don't init twice.
return;
}
[self setTranslatesAutoresizingMaskIntoConstraints:NO]; [self setTranslatesAutoresizingMaskIntoConstraints:NO];
@ -62,7 +65,7 @@ NS_ASSUME_NONNULL_BEGIN
self.titleLabel = [UILabel new]; self.titleLabel = [UILabel new];
self.titleLabel.textColor = [UIColor colorWithRGBHex:0x403e3b]; self.titleLabel.textColor = [UIColor colorWithRGBHex:0x403e3b];
self.titleLabel.font = [OWSSystemMessageCell titleFont]; self.titleLabel.font = [self titleFont];
self.titleLabel.numberOfLines = 0; self.titleLabel.numberOfLines = 0;
self.titleLabel.lineBreakMode = NSLineBreakByWordWrapping; self.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
[self.contentView addSubview:self.titleLabel]; [self.contentView addSubview:self.titleLabel];
@ -86,13 +89,13 @@ NS_ASSUME_NONNULL_BEGIN
UIImage *icon = [self iconForInteraction:self.interaction]; UIImage *icon = [self iconForInteraction:self.interaction];
self.imageView.image = [icon imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; self.imageView.image = [icon imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
self.imageView.tintColor = [self iconColorForInteraction:self.interaction]; self.imageView.tintColor = [self iconColorForInteraction:self.interaction];
self.titleLabel.textColor = [OWSSystemMessageCell textColor]; self.titleLabel.textColor = [self textColor];
[OWSSystemMessageCell applyTitleForInteraction:self.interaction label:self.titleLabel]; [self applyTitleForInteraction:self.interaction label:self.titleLabel];
[self setNeedsLayout]; [self setNeedsLayout];
} }
+ (UIColor *)textColor - (UIColor *)textColor
{ {
return [UIColor colorWithRGBHex:0x303030]; return [UIColor colorWithRGBHex:0x303030];
} }
@ -162,7 +165,7 @@ NS_ASSUME_NONNULL_BEGIN
return result; return result;
} }
+ (void)applyTitleForInteraction:(TSInteraction *)interaction label:(UILabel *)label - (void)applyTitleForInteraction:(TSInteraction *)interaction label:(UILabel *)label
{ {
OWSAssert(interaction); OWSAssert(interaction);
OWSAssert(label); OWSAssert(label);
@ -204,32 +207,32 @@ NS_ASSUME_NONNULL_BEGIN
} }
} }
+ (UIFont *)titleFont - (UIFont *)titleFont
{ {
return [UIFont ows_regularFontWithSize:13.f]; return [UIFont ows_regularFontWithSize:13.f];
} }
+ (CGFloat)hMargin - (CGFloat)hMargin
{ {
return 25.f; return 25.f;
} }
+ (CGFloat)topVMargin - (CGFloat)topVMargin
{ {
return 5.f; return 5.f;
} }
+ (CGFloat)bottomVMargin - (CGFloat)bottomVMargin
{ {
return 5.f; return 5.f;
} }
+ (CGFloat)hSpacing - (CGFloat)hSpacing
{ {
return 8.f; return 8.f;
} }
+ (CGFloat)iconSize - (CGFloat)iconSize
{ {
return 20.f; return 20.f;
} }
@ -238,36 +241,32 @@ NS_ASSUME_NONNULL_BEGIN
{ {
[super layoutSubviews]; [super layoutSubviews];
CGFloat maxTitleWidth = (self.contentView.width CGFloat maxTitleWidth = (self.contentView.width - ([self hMargin] * 2.f + [self hSpacing] + [self iconSize]));
- ([OWSSystemMessageCell hMargin] * 2.f + [OWSSystemMessageCell hSpacing] + [OWSSystemMessageCell iconSize]));
CGSize titleSize = [self.titleLabel sizeThatFits:CGSizeMake(maxTitleWidth, CGFLOAT_MAX)]; CGSize titleSize = [self.titleLabel sizeThatFits:CGSizeMake(maxTitleWidth, CGFLOAT_MAX)];
CGFloat contentWidth = ([OWSSystemMessageCell iconSize] + [OWSSystemMessageCell hSpacing] + titleSize.width); CGFloat contentWidth = ([self iconSize] + [self hSpacing] + titleSize.width);
self.imageView.frame = CGRectMake(round((self.contentView.width - contentWidth) * 0.5f), self.imageView.frame = CGRectMake(round((self.contentView.width - contentWidth) * 0.5f),
round((self.contentView.height - [OWSSystemMessageCell iconSize]) * 0.5f), round((self.contentView.height - [self iconSize]) * 0.5f),
[OWSSystemMessageCell iconSize], [self iconSize],
[OWSSystemMessageCell iconSize]); [self iconSize]);
self.titleLabel.frame = CGRectMake(round(self.imageView.right + [OWSSystemMessageCell hSpacing]), self.titleLabel.frame = CGRectMake(round(self.imageView.right + [self hSpacing]),
round((self.contentView.height - titleSize.height) * 0.5f), round((self.contentView.height - titleSize.height) * 0.5f),
ceil(titleSize.width + 1.f), ceil(titleSize.width + 1.f),
ceil(titleSize.height + 1.f)); ceil(titleSize.height + 1.f));
} }
+ (CGSize)cellSizeForInteraction:(TSInteraction *)interaction collectionViewWidth:(CGFloat)collectionViewWidth - (CGSize)cellSizeForInteraction:(TSInteraction *)interaction collectionViewWidth:(CGFloat)collectionViewWidth
{ {
CGSize result = CGSizeMake(collectionViewWidth, 0); CGSize result = CGSizeMake(collectionViewWidth, 0);
result.height += self.topVMargin; result.height += self.topVMargin;
result.height += self.bottomVMargin; result.height += self.bottomVMargin;
// Creating a UILabel to measure the layout is expensive, but it's the only self.titleLabel.font = [self titleFont];
// reliable way to do it. [self applyTitleForInteraction:interaction label:self.titleLabel];
UILabel *label = [UILabel new]; self.titleLabel.numberOfLines = 0;
label.font = [self titleFont]; self.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
[OWSSystemMessageCell applyTitleForInteraction:interaction label:label];
label.numberOfLines = 0;
label.lineBreakMode = NSLineBreakByWordWrapping;
CGFloat maxTitleWidth = (collectionViewWidth - ([self hMargin] * 2.f + [self hSpacing] + [self iconSize])); CGFloat maxTitleWidth = (collectionViewWidth - ([self hMargin] * 2.f + [self hSpacing] + [self iconSize]));
CGSize titleSize = [label sizeThatFits:CGSizeMake(maxTitleWidth, CGFLOAT_MAX)]; CGSize titleSize = [self.titleLabel sizeThatFits:CGSizeMake(maxTitleWidth, CGFLOAT_MAX)];
CGFloat contentHeight = ceil(MAX([self iconSize], titleSize.height)); CGFloat contentHeight = ceil(MAX([self iconSize], titleSize.height));
result.height += contentHeight; result.height += contentHeight;

@ -15,7 +15,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)configureWithInteraction:(TSUnreadIndicatorInteraction *)interaction; - (void)configureWithInteraction:(TSUnreadIndicatorInteraction *)interaction;
+ (CGSize)cellSizeForInteraction:(TSUnreadIndicatorInteraction *)interaction - (CGSize)cellSizeForInteraction:(TSUnreadIndicatorInteraction *)interaction
collectionViewWidth:(CGFloat)collectionViewWidth; collectionViewWidth:(CGFloat)collectionViewWidth;
@end @end

@ -49,7 +49,10 @@ NS_ASSUME_NONNULL_BEGIN
- (void)commontInit - (void)commontInit
{ {
OWSAssert(!self.bannerView); if (self.bannerView) {
// Don't init twice.
return;
}
[self setTranslatesAutoresizingMaskIntoConstraints:NO]; [self setTranslatesAutoresizingMaskIntoConstraints:NO];
@ -72,15 +75,15 @@ NS_ASSUME_NONNULL_BEGIN
[self.bannerView addSubview:self.bannerBottomHighlightView2]; [self.bannerView addSubview:self.bannerBottomHighlightView2];
self.titleLabel = [UILabel new]; self.titleLabel = [UILabel new];
self.titleLabel.text = [OWSUnreadIndicatorCell titleForInteraction:self.interaction]; self.titleLabel.text = [self titleForInteraction:self.interaction];
self.titleLabel.textColor = [UIColor colorWithRGBHex:0x403e3b]; self.titleLabel.textColor = [UIColor colorWithRGBHex:0x403e3b];
self.titleLabel.font = [OWSUnreadIndicatorCell titleFont]; self.titleLabel.font = [self titleFont];
[self.bannerView addSubview:self.titleLabel]; [self.bannerView addSubview:self.titleLabel];
self.subtitleLabel = [UILabel new]; self.subtitleLabel = [UILabel new];
self.subtitleLabel.text = [OWSUnreadIndicatorCell subtitleForInteraction:self.interaction]; self.subtitleLabel.text = [self subtitleForInteraction:self.interaction];
self.subtitleLabel.textColor = [UIColor ows_infoMessageBorderColor]; self.subtitleLabel.textColor = [UIColor ows_infoMessageBorderColor];
self.subtitleLabel.font = [OWSUnreadIndicatorCell subtitleFont]; self.subtitleLabel.font = [self subtitleFont];
self.subtitleLabel.numberOfLines = 0; self.subtitleLabel.numberOfLines = 0;
self.subtitleLabel.lineBreakMode = NSLineBreakByWordWrapping; self.subtitleLabel.lineBreakMode = NSLineBreakByWordWrapping;
self.subtitleLabel.textAlignment = NSTextAlignmentCenter; self.subtitleLabel.textAlignment = NSTextAlignmentCenter;
@ -103,23 +106,23 @@ NS_ASSUME_NONNULL_BEGIN
[self setNeedsLayout]; [self setNeedsLayout];
} }
+ (UIFont *)titleFont - (UIFont *)titleFont
{ {
return [UIFont ows_regularFontWithSize:16.f]; return [UIFont ows_regularFontWithSize:16.f];
} }
+ (UIFont *)subtitleFont - (UIFont *)subtitleFont
{ {
return [UIFont ows_regularFontWithSize:12.f]; return [UIFont ows_regularFontWithSize:12.f];
} }
+ (NSString *)titleForInteraction:(TSUnreadIndicatorInteraction *)interaction - (NSString *)titleForInteraction:(TSUnreadIndicatorInteraction *)interaction
{ {
return NSLocalizedString(@"MESSAGES_VIEW_UNREAD_INDICATOR", @"Indicator that separates read from unread messages.") return NSLocalizedString(@"MESSAGES_VIEW_UNREAD_INDICATOR", @"Indicator that separates read from unread messages.")
.uppercaseString; .uppercaseString;
} }
+ (NSString *)subtitleForInteraction:(TSUnreadIndicatorInteraction *)interaction - (NSString *)subtitleForInteraction:(TSUnreadIndicatorInteraction *)interaction
{ {
if (!interaction.hasMoreUnseenMessages) { if (!interaction.hasMoreUnseenMessages) {
return nil; return nil;
@ -137,32 +140,32 @@ NS_ASSUME_NONNULL_BEGIN
return [NSString stringWithFormat:subtitleFormat, loadMoreButtonName]; return [NSString stringWithFormat:subtitleFormat, loadMoreButtonName];
} }
+ (CGFloat)subtitleHMargin - (CGFloat)subtitleHMargin
{ {
return 20.f; return 20.f;
} }
+ (CGFloat)subtitleVSpacing - (CGFloat)subtitleVSpacing
{ {
return 3.f; return 3.f;
} }
+ (CGFloat)titleInnerHMargin - (CGFloat)titleInnerHMargin
{ {
return 10.f; return 10.f;
} }
+ (CGFloat)titleVMargin - (CGFloat)titleVMargin
{ {
return 5.5f; return 5.5f;
} }
+ (CGFloat)topVMargin - (CGFloat)topVMargin
{ {
return 5.f; return 5.f;
} }
+ (CGFloat)bottomVMargin - (CGFloat)bottomVMargin
{ {
return 5.f; return 5.f;
} }
@ -180,9 +183,9 @@ NS_ASSUME_NONNULL_BEGIN
// This layout logic assumes that the cell insets are symmetrical and can be deduced // This layout logic assumes that the cell insets are symmetrical and can be deduced
// from the cell frame. // from the cell frame.
CGRect bannerViewFrame = CGRectMake(-self.left, CGRect bannerViewFrame = CGRectMake(-self.left,
round(OWSUnreadIndicatorCell.topVMargin), round(self.topVMargin),
round(self.width + self.left * 2.f), round(self.width + self.left * 2.f),
round(self.titleLabel.height + OWSUnreadIndicatorCell.titleVMargin * 2.f)); round(self.titleLabel.height + self.titleVMargin * 2.f));
self.bannerView.frame = [self convertRect:bannerViewFrame toView:self.contentView]; self.bannerView.frame = [self convertRect:bannerViewFrame toView:self.contentView];
// The highlights should be 1px (not 1pt), so adapt their thickness to // The highlights should be 1px (not 1pt), so adapt their thickness to
@ -198,16 +201,15 @@ NS_ASSUME_NONNULL_BEGIN
if (self.subtitleLabel.text.length > 0) { if (self.subtitleLabel.text.length > 0) {
CGSize subtitleSize = [self.subtitleLabel CGSize subtitleSize = [self.subtitleLabel
sizeThatFits:CGSizeMake( sizeThatFits:CGSizeMake(self.contentView.width - [self subtitleHMargin] * 2.f, CGFLOAT_MAX)];
self.contentView.width - [OWSUnreadIndicatorCell subtitleHMargin] * 2.f, CGFLOAT_MAX)];
self.subtitleLabel.frame = CGRectMake(round((self.contentView.width - subtitleSize.width) * 0.5f), self.subtitleLabel.frame = CGRectMake(round((self.contentView.width - subtitleSize.width) * 0.5f),
round(self.bannerView.bottom + OWSUnreadIndicatorCell.subtitleVSpacing), round(self.bannerView.bottom + self.subtitleVSpacing),
ceil(subtitleSize.width), ceil(subtitleSize.width),
ceil(subtitleSize.height)); ceil(subtitleSize.height));
} }
} }
+ (CGSize)cellSizeForInteraction:(TSUnreadIndicatorInteraction *)interaction - (CGSize)cellSizeForInteraction:(TSUnreadIndicatorInteraction *)interaction
collectionViewWidth:(CGFloat)collectionViewWidth collectionViewWidth:(CGFloat)collectionViewWidth
{ {
CGSize result = CGSizeMake(collectionViewWidth, 0); CGSize result = CGSizeMake(collectionViewWidth, 0);
@ -220,7 +222,7 @@ NS_ASSUME_NONNULL_BEGIN
// Creating a UILabel to measure the layout is expensive, but it's the only // Creating a UILabel to measure the layout is expensive, but it's the only
// reliable way to do it. Unread indicators should be rare, so this is acceptable. // reliable way to do it. Unread indicators should be rare, so this is acceptable.
UILabel *label = [UILabel new]; UILabel *label = self.titleLabel;
label.font = [self titleFont]; label.font = [self titleFont];
label.text = title; label.text = title;
result.height += ceil([label sizeThatFits:CGSizeZero].height); result.height += ceil([label sizeThatFits:CGSizeZero].height);

Loading…
Cancel
Save