From c22a1f0475882d85e9939208ec52ba14a6f3186c Mon Sep 17 00:00:00 2001 From: Robert Moore Date: Mon, 8 Jul 2019 12:41:11 -0400 Subject: [PATCH] [Tabs] Deduplicate item view layout and contentFrame calculation. (#7796) Combines the code that performs layout and content frame calculation. Part of #7748 --- .../private/MDCTabBarViewItemView.m | 109 ++++++++---------- ...nlyShortTitleSizeToFitLTRLatin_11_2@2x.png | Bin 5771 -> 0 bytes ...lyShortTitleSizeToFitRTLArabic_11_2@2x.png | Bin 3984 -> 0 bytes 3 files changed, 47 insertions(+), 62 deletions(-) delete mode 100644 snapshot_test_goldens/goldens_64/MDCTabBarViewItemViewSnapshotTests/testTitleOnlyShortTitleSizeToFitLTRLatin_11_2@2x.png delete mode 100644 snapshot_test_goldens/goldens_64/MDCTabBarViewItemViewSnapshotTests/testTitleOnlyShortTitleSizeToFitRTLArabic_11_2@2x.png diff --git a/components/Tabs/src/TabBarView/private/MDCTabBarViewItemView.m b/components/Tabs/src/TabBarView/private/MDCTabBarViewItemView.m index a0b990748cf..6be5a16d0c0 100644 --- a/components/Tabs/src/TabBarView/private/MDCTabBarViewItemView.m +++ b/components/Tabs/src/TabBarView/private/MDCTabBarViewItemView.m @@ -99,14 +99,14 @@ - (void)commonMDCTabBarViewItemViewInit { - (CGRect)contentFrame { if (!self.iconImageView.image) { if (self.titleLabel.text.length) { - return [self contentFrameForTitleLabelInTextOnlyLayout]; + return [self contentFrameForTitleOnlyLayout]; } return CGRectZero; } if (self.titleLabel.text.length) { - return [self contentFrameForTitleLabelInTextAndImageLayout]; + return [self contentFrameForTitleAndImageLayout]; } - return [self contentFrameForImageViewInImageOnlyLayout]; + return [self contentFrameForImageOnlyLayout]; } #pragma mark - UIView @@ -119,56 +119,58 @@ - (void)layoutSubviews { } if (self.titleLabel.text.length && !self.iconImageView.image) { - [self layoutSubviewsTextOnly]; + self.titleLabel.frame = [self titleLabelFrameForTitleOnlyLayout]; return; } else if (!self.titleLabel.text.length && self.iconImageView.image) { - [self layoutSubviewsImageOnly]; + self.iconImageView.frame = [self iconImageViewFrameForImageOnlyLayout]; return; } else { - [self layoutSubviewsTextAndImage]; + CGRect titleLabelFrame = CGRectZero; + CGRect iconImageViewFrame = CGRectZero; + [self layoutTitleLabelFrame:&titleLabelFrame iconImageViewFrame:&iconImageViewFrame]; + self.titleLabel.frame = titleLabelFrame; + self.iconImageView.frame = iconImageViewFrame; } } -- (CGRect)contentFrameForTitleLabelInTextOnlyLayout { - CGRect insetBounds = UIEdgeInsetsInsetRect(self.bounds, kEdgeInsetsTextOnly); +- (CGRect)contentFrameForTitleOnlyLayout { + return [self titleLabelFrameForTitleOnlyLayout]; +} - CGSize contentSize = CGSizeMake(CGRectGetWidth(insetBounds), CGRectGetHeight(insetBounds)); - CGSize labelWidthFitSize = [self.titleLabel sizeThatFits:contentSize]; - CGSize labelSize = - CGSizeMake(labelWidthFitSize.width, MIN(contentSize.height, labelWidthFitSize.height)); - CGRect contentFrame = CGRectMake(CGRectGetMidX(insetBounds) - (labelWidthFitSize.width / 2), - CGRectGetMidY(insetBounds) - (labelWidthFitSize.height / 2), - labelSize.width, labelSize.height); - return MDCRectAlignToScale(contentFrame, self.window.screen.scale); +- (CGRect)contentFrameForImageOnlyLayout { + return [self iconImageViewFrameForImageOnlyLayout]; +} + +- (CGRect)contentFrameForTitleAndImageLayout { + CGRect titleLabelFrame = CGRectZero; + CGRect iconImageViewFrame = CGRectZero; + [self layoutTitleLabelFrame:&titleLabelFrame iconImageViewFrame:&iconImageViewFrame]; + return MDCRectAlignToScale( + CGRectMake(CGRectGetMinX(titleLabelFrame), CGRectGetMinY(iconImageViewFrame), + CGRectGetWidth(titleLabelFrame), + CGRectGetMaxY(titleLabelFrame) - CGRectGetMinY(iconImageViewFrame)), + self.window.screen.scale); } -- (void)layoutSubviewsTextOnly { +- (CGRect)titleLabelFrameForTitleOnlyLayout { CGRect contentFrame = UIEdgeInsetsInsetRect(self.bounds, kEdgeInsetsTextOnly); CGSize contentSize = CGSizeMake(CGRectGetWidth(contentFrame), CGRectGetHeight(contentFrame)); CGSize labelWidthFitSize = [self.titleLabel sizeThatFits:contentSize]; - CGSize labelSize = - CGSizeMake(contentSize.width, MIN(contentSize.height, labelWidthFitSize.height)); + CGSize labelSize = CGSizeMake(MIN(contentSize.width, labelWidthFitSize.width), + MIN(contentSize.height, labelWidthFitSize.height)); + // The label attempted to be taller than allowed by the content insets. Give it the full content + // width available. + if (labelWidthFitSize.height > contentSize.height) { + labelSize = CGSizeMake(contentSize.width, labelSize.height); + } CGRect labelFrame = CGRectMake(CGRectGetMidX(contentFrame) - (labelSize.width / 2), CGRectGetMidY(contentFrame) - (labelSize.height / 2), labelSize.width, labelSize.height); - self.titleLabel.frame = MDCRectAlignToScale(labelFrame, self.window.screen.scale); + return MDCRectAlignToScale(labelFrame, self.window.screen.scale); } -- (CGRect)contentFrameForImageViewInImageOnlyLayout { - CGRect insetBounds = UIEdgeInsetsInsetRect(self.bounds, kEdgeInsetsImageOnly); - - CGSize contentSize = CGSizeMake(CGRectGetWidth(insetBounds), CGRectGetHeight(insetBounds)); - CGSize imageIntrinsicContentSize = self.iconImageView.intrinsicContentSize; - CGSize imageFinalSize = CGSizeMake(MIN(contentSize.width, imageIntrinsicContentSize.width), - MIN(contentSize.height, imageIntrinsicContentSize.height)); - CGRect contentFrame = CGRectMake(CGRectGetMidX(insetBounds) - (imageFinalSize.width / 2), - CGRectGetMidY(insetBounds) - (imageFinalSize.height / 2), - imageFinalSize.width, imageFinalSize.height); - return MDCRectAlignToScale(contentFrame, self.window.screen.scale); -} - -- (void)layoutSubviewsImageOnly { +- (CGRect)iconImageViewFrameForImageOnlyLayout { CGRect contentFrame = UIEdgeInsetsInsetRect(self.bounds, kEdgeInsetsImageOnly); CGSize contentSize = CGSizeMake(CGRectGetWidth(contentFrame), CGRectGetHeight(contentFrame)); @@ -178,34 +180,11 @@ - (void)layoutSubviewsImageOnly { CGRect imageViewFrame = CGRectMake(CGRectGetMidX(contentFrame) - (imageFinalSize.width / 2), CGRectGetMidY(contentFrame) - (imageFinalSize.height / 2), imageFinalSize.width, imageFinalSize.height); - self.iconImageView.frame = MDCRectAlignToScale(imageViewFrame, self.window.screen.scale); -} - -- (CGRect)contentFrameForTitleLabelInTextAndImageLayout { - CGRect insetBounds = UIEdgeInsetsInsetRect(self.bounds, kEdgeInsetsTextAndImage); - - CGSize contentSize = CGSizeMake(CGRectGetWidth(insetBounds), CGRectGetHeight(insetBounds)); - CGSize labelSingleLineSize = self.titleLabel.intrinsicContentSize; - CGSize availableIconSize = CGSizeMake( - contentSize.width, contentSize.height - (kImageTitlePadding + labelSingleLineSize.height)); - - // Position the image, limiting it so that at least 1 line of text remains. - CGSize imageIntrinsicContentSize = self.iconImageView.intrinsicContentSize; - CGSize imageFinalSize = - CGSizeMake(MIN(imageIntrinsicContentSize.width, availableIconSize.width), - MIN(imageIntrinsicContentSize.height, availableIconSize.height)); - - // Now position the label from the bottom. - CGSize availableLabelSize = CGSizeMake( - contentSize.width, contentSize.height - (imageFinalSize.height + kImageTitlePadding)); - CGSize finalLabelSize = [self.titleLabel sizeThatFits:availableLabelSize]; - CGRect contentFrame = - CGRectMake(CGRectGetMidX(insetBounds) - (finalLabelSize.width / 2), - CGRectGetMinY(insetBounds), finalLabelSize.width, contentSize.height); - return MDCRectAlignToScale(contentFrame, self.window.screen.scale); + return MDCRectAlignToScale(imageViewFrame, self.window.screen.scale); } -- (void)layoutSubviewsTextAndImage { +- (void)layoutTitleLabelFrame:(CGRect *)titleLabelFrame + iconImageViewFrame:(CGRect *)iconImageViewFrame { CGRect contentFrame = UIEdgeInsetsInsetRect(self.bounds, kEdgeInsetsTextAndImage); CGSize contentSize = CGSizeMake(CGRectGetWidth(contentFrame), CGRectGetHeight(contentFrame)); @@ -222,7 +201,13 @@ - (void)layoutSubviewsTextAndImage { CGRectMake(CGRectGetMidX(contentFrame) - (imageFinalSize.width / 2), CGRectGetMinY(contentFrame), imageFinalSize.width, imageFinalSize.height); imageViewFrame = MDCRectAlignToScale(imageViewFrame, self.window.screen.scale); - self.iconImageView.frame = imageViewFrame; + if (iconImageViewFrame != NULL) { + *iconImageViewFrame = imageViewFrame; + } + + if (titleLabelFrame == NULL) { + return; + } // Now position the label from the bottom. CGSize availableLabelSize = @@ -233,7 +218,7 @@ - (void)layoutSubviewsTextAndImage { CGRectGetMaxY(contentFrame) - finalLabelSize.height, finalLabelSize.width, finalLabelSize.height); titleFrame = MDCRectAlignToScale(titleFrame, self.window.screen.scale); - self.titleLabel.frame = titleFrame; + *titleLabelFrame = titleFrame; } - (CGSize)intrinsicContentSize { diff --git a/snapshot_test_goldens/goldens_64/MDCTabBarViewItemViewSnapshotTests/testTitleOnlyShortTitleSizeToFitLTRLatin_11_2@2x.png b/snapshot_test_goldens/goldens_64/MDCTabBarViewItemViewSnapshotTests/testTitleOnlyShortTitleSizeToFitLTRLatin_11_2@2x.png deleted file mode 100644 index a4cb27382b2c5aeea1cceb158bdb4616583e19d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5771 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 xuKU;i+0^|BmmSwhPtLY)mpAG{{w5lz_I`U diff --git a/snapshot_test_goldens/goldens_64/MDCTabBarViewItemViewSnapshotTests/testTitleOnlyShortTitleSizeToFitRTLArabic_11_2@2x.png b/snapshot_test_goldens/goldens_64/MDCTabBarViewItemViewSnapshotTests/testTitleOnlyShortTitleSizeToFitRTLArabic_11_2@2x.png deleted file mode 100644 index c735ebfaec8f666933c0a95df52563f9ddd090ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3984 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 SD8R`NWMX*Uphn;8_J09o#2q&P