13
13
// limitations under the License.
14
14
15
15
#import < CoreGraphics/CoreGraphics.h>
16
+ #import < UIKit/UIKit.h>
16
17
17
18
#import " MDCBottomNavigationItemView.h"
18
19
28
29
// CGFloat doesn't lose precision.
29
30
static const CGFloat kMaxSizeDimension = 1000000 ;
30
31
static const CGFloat MDCBottomNavigationItemViewRippleOpacity = (CGFloat )0.150 ;
31
- static const CGFloat MDCBottomNavigationItemViewTitleFontSize = 12 ;
32
32
33
33
// Selection indicator animation details.
34
34
static const CGFloat kSelectionIndicatorTransformAnimationDuration = 0.17 ;
@@ -115,7 +115,7 @@ - (instancetype)initWithFrame:(CGRect)frame {
115
115
116
116
_label = [[UILabel alloc ] initWithFrame: CGRectZero ];
117
117
_label.text = _title;
118
- _label.font = [UIFont systemFontOfSize: MDCBottomNavigationItemViewTitleFontSize ];
118
+ _label.font = [UIFont systemFontOfSize: 12 ];
119
119
_label.textAlignment = NSTextAlignmentCenter;
120
120
_label.textColor = _selectedItemTitleColor;
121
121
_label.lineBreakMode = NSLineBreakByTruncatingTail;
@@ -128,12 +128,11 @@ - (instancetype)initWithFrame:(CGRect)frame {
128
128
129
129
_badge = [[MDCBadgeView alloc ] initWithFrame: CGRectZero ];
130
130
_badge.isAccessibilityElement = NO ;
131
-
132
131
[_button addSubview: _iconImageView];
133
132
[_button addSubview: _label];
134
133
[_button addSubview: _badge];
135
134
_badge.hidden = YES ;
136
-
135
+ _iconContainerView = [[UIView alloc ] initWithFrame: CGRectZero ];
137
136
_rippleTouchController = [[MDCRippleTouchController alloc ] initWithView: self ];
138
137
_rippleTouchController.rippleView .rippleStyle = MDCRippleStyleUnbounded;
139
138
}
@@ -170,7 +169,12 @@ - (CGSize)sizeThatFitsForVerticalLayout {
170
169
}
171
170
172
171
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
+ }
174
178
CGRect iconFrame = CGRectMake (0 , 0 , iconSize.width , iconSize.height );
175
179
CGSize badgeSize = [_badge sizeThatFits: maxSize];
176
180
CGPoint badgeCenter = [self badgeCenterFromIconFrame: iconFrame isRTL: NO ];
@@ -194,7 +198,12 @@ - (CGSize)sizeThatFitsForHorizontalLayout {
194
198
}
195
199
196
200
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
+ }
198
207
CGRect iconFrame = CGRectMake (0 , 0 , iconSize.width , iconSize.height );
199
208
CGSize badgeSize = [_badge sizeThatFits: maxSize];
200
209
CGPoint badgeCenter = [self badgeCenterFromIconFrame: iconFrame isRTL: NO ];
@@ -234,7 +243,12 @@ - (void)calculateVerticalLayoutInBounds:(CGRect)contentBounds
234
243
235
244
// Determine the intrinsic size of the label, icon, and combined content
236
245
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
+ }
238
252
CGSize labelSize = [self .label sizeThatFits: contentBoundingRect.size];
239
253
CGFloat iconHeight = iconImageViewSize.height ;
240
254
CGFloat labelHeight = labelSize.height ;
@@ -245,12 +259,11 @@ - (void)calculateVerticalLayoutInBounds:(CGRect)contentBounds
245
259
246
260
// Determine the position of the label and icon
247
261
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
+ );
254
267
CGPoint iconImageViewCenter = CGPointMake (centerX, iconImageViewCenterY);
255
268
// Ignore the horizontal titlePositionAdjustment in a vertical layout to match UITabBar behavior.
256
269
CGFloat centerY;
@@ -290,7 +303,12 @@ - (void)calculateHorizontalLayoutInBounds:(CGRect)contentBounds
290
303
}
291
304
// Determine the intrinsic size of the label and icon
292
305
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
+ }
294
312
CGSize maxLabelSize = CGSizeMake (
295
313
contentBoundingRect.size .width - self.contentHorizontalMargin - iconImageViewSize.width ,
296
314
contentBoundingRect.size .height );
@@ -373,13 +391,21 @@ - (void)centerLayoutAnimated:(BOOL)animated {
373
391
if (animated) {
374
392
[UIView animateWithDuration: kMDCBottomNavigationItemViewSelectionAnimationDuration
375
393
animations: ^(void ) {
376
- self.iconImageView .center = iconImageViewCenter;
394
+ if (_enableSquareImages) {
395
+ self.iconContainerView .center = iconImageViewCenter;
396
+ } else {
397
+ self.iconImageView .center = iconImageViewCenter;
398
+ }
377
399
_badge.center =
378
400
[self badgeCenterFromIconFrame: CGRectStandardize (iconImageViewFrame)
379
401
isRTL: isRTL];
380
402
}];
381
403
} else {
382
- self.iconImageView .center = iconImageViewCenter;
404
+ if (_enableSquareImages) {
405
+ self.iconContainerView .center = iconImageViewCenter;
406
+ } else {
407
+ self.iconImageView .center = iconImageViewCenter;
408
+ }
383
409
_badge.center = [self badgeCenterFromIconFrame: CGRectStandardize (iconImageViewFrame)
384
410
isRTL: isRTL];
385
411
}
@@ -390,7 +416,12 @@ - (void)centerLayoutAnimated:(BOOL)animated {
390
416
} else {
391
417
self.label .textAlignment = NSTextAlignmentRight;
392
418
}
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;
394
425
_badge.center = [self badgeCenterFromIconFrame: CGRectStandardize (iconImageViewFrame)
395
426
isRTL: isRTL];
396
427
}
@@ -621,9 +652,15 @@ - (void)setSelectedItemTitleColor:(nullable UIColor *)selectedItemTitleColor {
621
652
622
653
- (void )setImage : (nullable UIImage *)image {
623
654
_image = [image imageWithRenderingMode: UIImageRenderingModeAlwaysTemplate];
624
-
625
655
// _image updates unselected state
626
656
// _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
+ }
627
664
if (!self.selected || (self.selected && !self.selectedImage )) {
628
665
self.iconImageView .image = _image;
629
666
self.iconImageView .tintColor =
@@ -737,7 +774,11 @@ - (void)setShowsSelectionIndicator:(BOOL)showsSelectionIndicator {
737
774
_selectionIndicator.backgroundColor = _selectionIndicatorColor;
738
775
_selectionIndicator.hidden = !_selected;
739
776
[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
+ }
741
782
} else {
742
783
[_selectionIndicator removeFromSuperview ];
743
784
_selectionIndicator = nil ;
@@ -973,16 +1014,27 @@ - (CGPoint)iconPosition {
973
1014
CGPoint midPoint = [self midPoint ];
974
1015
CGFloat indicatorMidX = CGRectGetMidX (_selectionIndicator.frame );
975
1016
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
+ }
980
1028
return CGPointMake (iconX, iconY);
981
1029
}
982
1030
983
1031
- (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
+ }
986
1038
}
987
1039
988
1040
#pragma mark - Anchored Label
@@ -1045,7 +1097,11 @@ - (CGFloat)labelXForHorizontalLayoutWithRTLState:(BOOL)isRTL {
1045
1097
1046
1098
- (CGFloat )labelYForHorizontalLayout {
1047
1099
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
+ }
1049
1105
}
1050
1106
1051
1107
#pragma mark - Branched anchored layout methods
@@ -1105,7 +1161,11 @@ - (void)centerAnchoredLayoutVertical {
1105
1161
CGFloat iconY = iconPosition.y ;
1106
1162
CGSize iconSize = [self iconSize ];
1107
1163
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
+ }
1109
1169
1110
1170
CGSize labelSize = [self labelSize ];
1111
1171
CGRect adjustedLabelBounds = CGRectMake (0 , 0 , labelSize.width , labelSize.height );
@@ -1139,8 +1199,11 @@ - (void)centerAnchoredLayoutHorizontal {
1139
1199
CGFloat iconY = iconPosition.y ;
1140
1200
CGSize iconSize = [self iconSize ];
1141
1201
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
+ }
1144
1207
CGFloat labelX = [self labelXForHorizontalLayoutWithRTLState: isRTL];
1145
1208
CGFloat labelY = [self labelYForHorizontalLayout ];
1146
1209
if (self.enableVerticalLayout ) {
@@ -1190,6 +1253,45 @@ - (BOOL)isTitleHiddenInAnchoredLayout {
1190
1253
_titleVisibility == MDCBottomNavigationBarTitleVisibilityNever);
1191
1254
}
1192
1255
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
+
1193
1295
@end
1194
1296
1195
1297
NS_ASSUME_NONNULL_END
0 commit comments