1313// limitations under the License.
1414
1515#import < CoreGraphics/CoreGraphics.h>
16+ #import < UIKit/UIKit.h>
1617
1718#import " MDCBottomNavigationItemView.h"
1819
2829// CGFloat doesn't lose precision.
2930static const CGFloat kMaxSizeDimension = 1000000 ;
3031static const CGFloat MDCBottomNavigationItemViewRippleOpacity = (CGFloat)0.150 ;
31- static const CGFloat MDCBottomNavigationItemViewTitleFontSize = 12 ;
3232
3333// Selection indicator animation details.
3434static const CGFloat kSelectionIndicatorTransformAnimationDuration = 0.17 ;
@@ -115,7 +115,7 @@ - (instancetype)initWithFrame:(CGRect)frame {
115115
116116 _label = [[UILabel alloc ] initWithFrame: CGRectZero];
117117 _label.text = _title;
118- _label.font = [UIFont systemFontOfSize: MDCBottomNavigationItemViewTitleFontSize ];
118+ _label.font = [UIFont systemFontOfSize: 12 ];
119119 _label.textAlignment = NSTextAlignmentCenter;
120120 _label.textColor = _selectedItemTitleColor;
121121 _label.lineBreakMode = NSLineBreakByTruncatingTail;
@@ -128,12 +128,11 @@ - (instancetype)initWithFrame:(CGRect)frame {
128128
129129 _badge = [[MDCBadgeView alloc ] initWithFrame: CGRectZero];
130130 _badge.isAccessibilityElement = NO ;
131-
132131 [_button addSubview: _iconImageView];
133132 [_button addSubview: _label];
134133 [_button addSubview: _badge];
135134 _badge.hidden = YES ;
136-
135+ _iconContainerView = [[UIView alloc ] initWithFrame: CGRectZero];
137136 _rippleTouchController = [[MDCRippleTouchController alloc ] initWithView: self ];
138137 _rippleTouchController.rippleView .rippleStyle = MDCRippleStyleUnbounded;
139138 }
@@ -170,7 +169,12 @@ - (CGSize)sizeThatFitsForVerticalLayout {
170169 }
171170
172171 CGSize maxSize = CGSizeMake (kMaxSizeDimension , kMaxSizeDimension );
173- CGSize iconSize = [self .iconImageView sizeThatFits: maxSize];
172+ CGSize iconSize;
173+ if (_enableSquareImages) {
174+ iconSize = CGSizeMake (24 , 24 );
175+ } else {
176+ iconSize = [self .iconImageView sizeThatFits: maxSize];
177+ }
174178 CGRect iconFrame = CGRectMake (0 , 0 , iconSize.width , iconSize.height );
175179 CGSize badgeSize = [_badge sizeThatFits: maxSize];
176180 CGPoint badgeCenter = [self badgeCenterFromIconFrame: iconFrame isRTL: NO ];
@@ -194,7 +198,12 @@ - (CGSize)sizeThatFitsForHorizontalLayout {
194198 }
195199
196200 CGSize maxSize = CGSizeMake (kMaxSizeDimension , kMaxSizeDimension );
197- CGSize iconSize = [self .iconImageView sizeThatFits: maxSize];
201+ CGSize iconSize;
202+ if (_enableSquareImages) {
203+ iconSize = CGSizeMake (24 , 24 );
204+ } else {
205+ iconSize = [self .iconImageView sizeThatFits: maxSize];
206+ }
198207 CGRect iconFrame = CGRectMake (0 , 0 , iconSize.width , iconSize.height );
199208 CGSize badgeSize = [_badge sizeThatFits: maxSize];
200209 CGPoint badgeCenter = [self badgeCenterFromIconFrame: iconFrame isRTL: NO ];
@@ -234,7 +243,12 @@ - (void)calculateVerticalLayoutInBounds:(CGRect)contentBounds
234243
235244 // Determine the intrinsic size of the label, icon, and combined content
236245 CGRect contentBoundingRect = CGRectStandardize (contentBounds);
237- CGSize iconImageViewSize = [self .iconImageView sizeThatFits: contentBoundingRect.size];
246+ CGSize iconImageViewSize;
247+ if (_enableSquareImages) {
248+ iconImageViewSize = CGSizeMake (24 , 24 );
249+ } else {
250+ iconImageViewSize = [self .iconImageView sizeThatFits: contentBoundingRect.size];
251+ }
238252 CGSize labelSize = [self .label sizeThatFits: contentBoundingRect.size];
239253 CGFloat iconHeight = iconImageViewSize.height ;
240254 CGFloat labelHeight = labelSize.height ;
@@ -245,12 +259,11 @@ - (void)calculateVerticalLayoutInBounds:(CGRect)contentBounds
245259
246260 // Determine the position of the label and icon
247261 CGFloat centerX = CGRectGetMidX (contentBoundingRect);
248- CGFloat iconImageViewCenterY =
249- MAX (floor (CGRectGetMidY (contentBoundingRect) - totalContentHeight / 2 +
250- iconHeight / 2 ), // Content centered
251- floor (CGRectGetMinY (contentBoundingRect) +
252- iconHeight / 2 ) // Pinned to top of bounding rect.
253- );
262+ CGFloat iconImageViewCenterY = MAX (
263+ floor (CGRectGetMidY (contentBoundingRect) - totalContentHeight / 2 +
264+ iconHeight / 2 ), // Content centered
265+ floor (CGRectGetMinY (contentBoundingRect) + iconHeight / 2 ) // Pinned to top of bounding rect.
266+ );
254267 CGPoint iconImageViewCenter = CGPointMake (centerX, iconImageViewCenterY);
255268 // Ignore the horizontal titlePositionAdjustment in a vertical layout to match UITabBar behavior.
256269 CGFloat centerY;
@@ -290,7 +303,12 @@ - (void)calculateHorizontalLayoutInBounds:(CGRect)contentBounds
290303 }
291304 // Determine the intrinsic size of the label and icon
292305 CGRect contentBoundingRect = CGRectStandardize (contentBounds);
293- CGSize iconImageViewSize = [self .iconImageView sizeThatFits: contentBoundingRect.size];
306+ CGSize iconImageViewSize;
307+ if (_enableSquareImages) {
308+ iconImageViewSize = CGSizeMake (24 , 24 );
309+ } else {
310+ iconImageViewSize = [self .iconImageView sizeThatFits: contentBoundingRect.size];
311+ }
294312 CGSize maxLabelSize = CGSizeMake (
295313 contentBoundingRect.size .width - self.contentHorizontalMargin - iconImageViewSize.width ,
296314 contentBoundingRect.size .height );
@@ -373,13 +391,21 @@ - (void)centerLayoutAnimated:(BOOL)animated {
373391 if (animated) {
374392 [UIView animateWithDuration: kMDCBottomNavigationItemViewSelectionAnimationDuration
375393 animations: ^(void ) {
376- self.iconImageView .center = iconImageViewCenter;
394+ if (_enableSquareImages) {
395+ self.iconContainerView .center = iconImageViewCenter;
396+ } else {
397+ self.iconImageView .center = iconImageViewCenter;
398+ }
377399 _badge.center =
378400 [self badgeCenterFromIconFrame: CGRectStandardize (iconImageViewFrame)
379401 isRTL: isRTL];
380402 }];
381403 } else {
382- self.iconImageView .center = iconImageViewCenter;
404+ if (_enableSquareImages) {
405+ self.iconContainerView .center = iconImageViewCenter;
406+ } else {
407+ self.iconImageView .center = iconImageViewCenter;
408+ }
383409 _badge.center = [self badgeCenterFromIconFrame: CGRectStandardize (iconImageViewFrame)
384410 isRTL: isRTL];
385411 }
@@ -390,7 +416,12 @@ - (void)centerLayoutAnimated:(BOOL)animated {
390416 } else {
391417 self.label .textAlignment = NSTextAlignmentRight;
392418 }
393- self.iconImageView .center = iconImageViewCenter;
419+ if (_enableSquareImages) {
420+ self.iconContainerView .center = iconImageViewCenter;
421+ } else {
422+ self.iconImageView .center = iconImageViewCenter;
423+ }
424+ self.iconContainerView .center = iconImageViewCenter;
394425 _badge.center = [self badgeCenterFromIconFrame: CGRectStandardize (iconImageViewFrame)
395426 isRTL: isRTL];
396427 }
@@ -621,9 +652,15 @@ - (void)setSelectedItemTitleColor:(nullable UIColor *)selectedItemTitleColor {
621652
622653- (void )setImage : (nullable UIImage *)image {
623654 _image = [image imageWithRenderingMode: UIImageRenderingModeAlwaysTemplate];
624-
625655 // _image updates unselected state
626656 // _image updates selected state IF there is no selectedImage
657+ if (image == nil ) {
658+ self.iconContainerView .frame = CGRectZero;
659+ return ;
660+ }
661+ if (_enableSquareImages) {
662+ [self setupIconContainerView ];
663+ }
627664 if (!self.selected || (self.selected && !self.selectedImage )) {
628665 self.iconImageView .image = _image;
629666 self.iconImageView .tintColor =
@@ -737,7 +774,11 @@ - (void)setShowsSelectionIndicator:(BOOL)showsSelectionIndicator {
737774 _selectionIndicator.backgroundColor = _selectionIndicatorColor;
738775 _selectionIndicator.hidden = !_selected;
739776 [self commitSelectionIndicatorState ];
740- [self .button insertSubview: _selectionIndicator belowSubview: _iconImageView];
777+ if (_enableSquareImages) {
778+ [self .button insertSubview: _selectionIndicator belowSubview: _iconContainerView];
779+ } else {
780+ [self .button insertSubview: _selectionIndicator belowSubview: _iconImageView];
781+ }
741782 } else {
742783 [_selectionIndicator removeFromSuperview ];
743784 _selectionIndicator = nil ;
@@ -973,16 +1014,27 @@ - (CGPoint)iconPosition {
9731014 CGPoint midPoint = [self midPoint ];
9741015 CGFloat indicatorMidX = CGRectGetMidX (_selectionIndicator.frame );
9751016
976- CGFloat iconX = indicatorMidX - CGRectGetMidX (_iconImageView.bounds );
977- CGFloat iconY = midPoint.y + (_selectionIndicatorSize.height * 0.5 ) -
978- CGRectGetMidY (_iconImageView.bounds ) + kIconVerticalOffset ;
979-
1017+ CGFloat iconX;
1018+ CGFloat iconY;
1019+ if (_enableSquareImages) {
1020+ iconX = indicatorMidX - CGRectGetMidX (_iconContainerView.bounds );
1021+ iconY = midPoint.y + (_selectionIndicatorSize.height * 0.5 ) -
1022+ CGRectGetMidY (_iconContainerView.bounds ) + kIconVerticalOffset ;
1023+ } else {
1024+ iconX = indicatorMidX - CGRectGetMidX (_iconImageView.bounds );
1025+ iconY = midPoint.y + (_selectionIndicatorSize.height * 0.5 ) -
1026+ CGRectGetMidY (_iconImageView.bounds ) + kIconVerticalOffset ;
1027+ }
9801028 return CGPointMake (iconX, iconY);
9811029}
9821030
9831031- (CGSize)iconSize {
984- CGSize maxSize = CGSizeMake (kMaxSizeDimension , kMaxSizeDimension );
985- return [_iconImageView sizeThatFits: maxSize];
1032+ if (_enableSquareImages) {
1033+ return _iconContainerView.frame .size ;
1034+ } else {
1035+ CGSize maxSize = CGSizeMake (kMaxSizeDimension , kMaxSizeDimension );
1036+ return [_iconImageView sizeThatFits: maxSize];
1037+ }
9861038}
9871039
9881040#pragma mark - Anchored Label
@@ -1045,7 +1097,11 @@ - (CGFloat)labelXForHorizontalLayoutWithRTLState:(BOOL)isRTL {
10451097
10461098- (CGFloat)labelYForHorizontalLayout {
10471099 CGPoint midPoint = [self midPoint ];
1048- return midPoint.y + CGRectGetMidY (_iconImageView.bounds );
1100+ if (_enableSquareImages) {
1101+ return midPoint.y + CGRectGetMidY (_iconContainerView.bounds );
1102+ } else {
1103+ return midPoint.y + CGRectGetMidY (_iconImageView.bounds );
1104+ }
10491105}
10501106
10511107#pragma mark - Branched anchored layout methods
@@ -1105,7 +1161,11 @@ - (void)centerAnchoredLayoutVertical {
11051161 CGFloat iconY = iconPosition.y ;
11061162 CGSize iconSize = [self iconSize ];
11071163 CGRect iconFrame = (CGRectMake (iconX, iconY, iconSize.width , iconSize.height ));
1108- _iconImageView.frame = iconFrame;
1164+ if (_enableSquareImages) {
1165+ _iconContainerView.frame = iconFrame;
1166+ } else {
1167+ _iconImageView.frame = iconFrame;
1168+ }
11091169
11101170 CGSize labelSize = [self labelSize ];
11111171 CGRect adjustedLabelBounds = CGRectMake (0 , 0 , labelSize.width , labelSize.height );
@@ -1139,8 +1199,11 @@ - (void)centerAnchoredLayoutHorizontal {
11391199 CGFloat iconY = iconPosition.y ;
11401200 CGSize iconSize = [self iconSize ];
11411201 CGRect iconFrame = CGRectIntegral (CGRectMake (iconX, iconY, iconSize.width , iconSize.height ));
1142- _iconImageView.frame = iconFrame;
1143-
1202+ if (_enableSquareImages) {
1203+ _iconContainerView.frame = iconFrame;
1204+ } else {
1205+ _iconImageView.frame = iconFrame;
1206+ }
11441207 CGFloat labelX = [self labelXForHorizontalLayoutWithRTLState: isRTL];
11451208 CGFloat labelY = [self labelYForHorizontalLayout ];
11461209 if (self.enableVerticalLayout ) {
@@ -1190,6 +1253,45 @@ - (BOOL)isTitleHiddenInAnchoredLayout {
11901253 _titleVisibility == MDCBottomNavigationBarTitleVisibilityNever);
11911254}
11921255
1256+ - (void )setEnableSquareImages : (BOOL )enableSquareImages {
1257+ if (_enableSquareImages == enableSquareImages) {
1258+ return ;
1259+ }
1260+ _enableSquareImages = enableSquareImages;
1261+ if (_enableSquareImages) {
1262+ [self setupIconContainerView ];
1263+ } else {
1264+ _iconImageView.translatesAutoresizingMaskIntoConstraints = YES ;
1265+ [_iconContainerView removeFromSuperview ];
1266+ [_button addSubview: _iconImageView];
1267+ }
1268+ [_button bringSubviewToFront: _badge];
1269+ }
1270+
1271+ - (void )setupIconContainerView {
1272+ if (!_enableSquareImages) {
1273+ return ;
1274+ }
1275+ _iconContainerView.userInteractionEnabled = NO ;
1276+ [_iconContainerView addSubview: _iconImageView];
1277+ [_button addSubview: _iconContainerView];
1278+ _iconImageView.translatesAutoresizingMaskIntoConstraints = NO ;
1279+ if (_image != nil ) {
1280+ _iconContainerView.frame = CGRectMake (0 , 0 , 24 , 24 );
1281+ UIImageSymbolConfiguration *symbolConfiguration =
1282+ [UIImageSymbolConfiguration configurationWithPointSize: 15.5
1283+ weight: UIImageSymbolWeightMedium];
1284+ _iconImageView.preferredSymbolConfiguration = symbolConfiguration;
1285+ [_iconImageView sizeToFit ];
1286+ [NSLayoutConstraint activateConstraints: @[
1287+ [_iconImageView.centerXAnchor constraintEqualToAnchor: _iconContainerView.centerXAnchor],
1288+ [_iconImageView.centerYAnchor constraintEqualToAnchor: _iconContainerView.centerYAnchor],
1289+ ]];
1290+ } else {
1291+ self.iconContainerView .frame = CGRectZero;
1292+ }
1293+ }
1294+
11931295@end
11941296
11951297NS_ASSUME_NONNULL_END
0 commit comments