Skip to content
Permalink
Browse files

[Tabs] Add support for `selectedImage` from UITabBarItem. (#7814)

MDCTabBarView needs to support `selectedImage` from UITabBarItem. Some clients will want to use different images for selected/unselected states.

Closes #7798
  • Loading branch information
romoore committed Jul 9, 2019
1 parent 71b103e commit 1ead0b6fac7ba10da81379c19ba15bf59a15a8c0
@@ -43,6 +43,7 @@
/// Default duration in seconds for selection change animations.
static const NSTimeInterval kSelectionChangeAnimationDuration = 0.3;

static NSString *const kSelectedImageKeyPath = @"selectedImage";
static NSString *const kImageKeyPath = @"image";
static NSString *const kTitleKeyPath = @"title";
static NSString *const kAccessibilityLabelKeyPath = @"accessibilityLabel";
@@ -198,7 +199,8 @@ - (void)setItems:(NSArray<UITabBarItem *> *)items {
? UIAccessibilityTraitButton
: item.accessibilityTraits;
mdcItemView.titleLabel.textColor = [self titleColorForState:UIControlStateNormal];
mdcItemView.iconImageView.image = item.image;
mdcItemView.image = item.image;
mdcItemView.selectedImage = item.selectedImage;
mdcItemView.rippleTouchController.rippleView.rippleColor = self.rippleColor;
itemView = mdcItemView;
}
@@ -416,6 +418,10 @@ - (void)addObserversToTabBarItems {
forKeyPath:kImageKeyPath
options:NSKeyValueObservingOptionNew
context:kKVOContextMDCTabBarView];
[item addObserver:self
forKeyPath:kSelectedImageKeyPath
options:NSKeyValueObservingOptionNew
context:kKVOContextMDCTabBarView];
[item addObserver:self
forKeyPath:kTitleKeyPath
options:NSKeyValueObservingOptionNew
@@ -442,6 +448,7 @@ - (void)addObserversToTabBarItems {
- (void)removeObserversFromTabBarItems {
for (UITabBarItem *item in self.items) {
[item removeObserver:self forKeyPath:kImageKeyPath context:kKVOContextMDCTabBarView];
[item removeObserver:self forKeyPath:kSelectedImageKeyPath context:kKVOContextMDCTabBarView];
[item removeObserver:self forKeyPath:kTitleKeyPath context:kKVOContextMDCTabBarView];
[item removeObserver:self
forKeyPath:kAccessibilityLabelKeyPath
@@ -481,7 +488,13 @@ - (void)observeValueForKeyPath:(NSString *)keyPath
newValue = nil;
}
if ([keyPath isEqualToString:kImageKeyPath]) {
tabBarItemView.iconImageView.image = newValue;
tabBarItemView.image = newValue;
[tabBarItemView invalidateIntrinsicContentSize];
[tabBarItemView setNeedsLayout];
[self invalidateIntrinsicContentSize];
[self setNeedsLayout];
} else if ([keyPath isEqualToString:kSelectedImageKeyPath]) {
tabBarItemView.selectedImage = newValue;
[tabBarItemView invalidateIntrinsicContentSize];
[tabBarItemView setNeedsLayout];
[self invalidateIntrinsicContentSize];
@@ -21,6 +21,12 @@
/** A basic view that displays a title and image for a tab bar item within MDCTabBarView. */
@interface MDCTabBarViewItemView : UIView <MDCTabBarViewCustomViewable>

/** The image to display when unselected. */
@property(nonatomic, strong) UIImage *image;

/** The image to display when selected. */
@property(nonatomic, strong) UIImage *selectedImage;

/** The image view to display the icon. */
@property(nonatomic, strong) UIImageView *iconImageView;

@@ -48,10 +48,15 @@

@interface MDCTabBarViewItemView ()

/** Indicates the selection status of this item view. */
@property(nonatomic, assign, getter=isSelected) BOOL selected;

@end

@implementation MDCTabBarViewItemView

@synthesize selectedImage = _selectedImage;

#pragma mark - Init

- (instancetype)initWithFrame:(CGRect)frame {
@@ -237,6 +242,24 @@ - (CGSize)sizeThatFitsTextAndImage:(CGSize)size {
kEdgeInsetsTextAndImage.bottom));
}

#pragma mark - MDCTabBarViewItemView properties

- (void)setImage:(UIImage *)image {
_image = image;
self.iconImageView.image = self.selected ? self.selectedImage : self.image;
[self setNeedsLayout];
}

- (void)setSelectedImage:(UIImage *)selectedImage {
_selectedImage = selectedImage;
self.iconImageView.image = self.selected ? self.selectedImage : self.image;
[self setNeedsLayout];
}

- (UIImage *)selectedImage {
return _selectedImage ?: self.image;
}

#pragma mark - UIAccessibility

- (NSString *)accessibilityLabel {
@@ -248,6 +271,21 @@ - (NSString *)accessibilityLabel {
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
// TODO(https://github.com/material-components/material-components-ios/issues/7801): Add
// item view support for selection.
void (^animationBlock)(void) = ^{
self->_selected = selected;
if (selected) {
self.iconImageView.image = self.selectedImage ?: self.image;
} else {
self.iconImageView.image = self.image;
}
};

if (animated) {
[UIView animateWithDuration:0.3 animations:animationBlock];
} else {
animationBlock();
}

// TODO(https://github.com/material-components/material-components-ios/issues/7798): Switch to
// using the selected image.
}
@@ -371,7 +371,7 @@ - (void)testItemsWithMixedTitlesAndImagesRTLArabic {

#pragma mark - Selection

- (void)testChangingSelectedItemIgnoresSelectedImage {
- (void)testChangingSelectedItemUsesSelectedImage {
// Given
self.tabBarView.bounds = CGRectMake(0, 0, 360, kExpectedHeightTitlesAndIcons);
self.item1.image = self.typicalIcon1;
@@ -480,7 +480,13 @@ - (void)testChangingImageOfUnselectedItemAfterAddingToBar {
[self generateSnapshotAndVerifyForView:self.tabBarView];
}

- (void)testChangingImageOfSelectedItemAfterAddingToBar {
/**
This order of operations has no effect because UITabBarItem assigns a copy the value set for
@c image to @c selectedImage if it is currently @c nil. Since MDCTabBarView can only retrieve
images from the public API of UITabBarItem, there is a value for @c selectedImage. As a result,
changing the value of @c image will not update @c selectedImage.
*/
- (void)testChangingImageOfSelectedItemAfterAddingToBarDoesNothing {
// Given
self.tabBarView.bounds = CGRectMake(0, 0, 360, kExpectedHeightTitlesAndIcons);
UITabBarItem *item1 = [[UITabBarItem alloc] initWithTitle:@"One" image:self.typicalIcon1 tag:0];
@@ -512,7 +518,7 @@ - (void)testChangingSelectedImageOfUnselectedItemAfterAddingToBarDoesNothing {
[self generateSnapshotAndVerifyForView:self.tabBarView];
}

- (void)testChangingSelectedImageOfSelectedItemAfterAddingToBarDoesNothing {
- (void)testChangingSelectedImageOfSelectedItemAfterAddingToBarUpdatesView {
// Given
self.tabBarView.bounds = CGRectMake(0, 0, 360, kExpectedHeightTitlesAndIcons);
UITabBarItem *item1 = [[UITabBarItem alloc] initWithTitle:@"One" image:self.typicalIcon1 tag:0];
Binary file not shown.

0 comments on commit 1ead0b6

Please sign in to comment.
You can’t perform that action at this time.