Skip to content

Commit

Permalink
[Tabs2] Add items and selectedItems API to the MDCTabBarView (#7656)
Browse files Browse the repository at this point in the history
Implement the items and selectedItems properties in the MDCTabBarView.
Adds test for these two properties.

closes #7646
  • Loading branch information
leonmz authored and Robert Moore committed Jun 21, 2019
1 parent ec9a941 commit 76b14be
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 1 deletion.
6 changes: 6 additions & 0 deletions components/Tabs2/src/MDCTabBarView.h
Expand Up @@ -19,4 +19,10 @@
*/
__attribute__((objc_subclassing_restricted)) @interface MDCTabBarView : UIScrollView

/** The set of items displayed in the Tab bar. */
@property(nonnull, nonatomic, copy) NSArray<UITabBarItem *> *items;

/** The currently-selected item in the Tab bar. */
@property(nullable, nonatomic, strong) UITabBarItem *selectedItem;

@end
46 changes: 46 additions & 0 deletions components/Tabs2/src/MDCTabBarView.m
Expand Up @@ -19,6 +19,52 @@

@implementation MDCTabBarView

#pragma mark - Initialization

- (instancetype)init {
self = [super init];
if (self) {
_items = @[];
}
return self;
}

#pragma mark - Properties

- (void)setItems:(NSArray<UITabBarItem *> *)items {
NSParameterAssert(items);

if (self.items == items || [self.items isEqual:items]) {
return;
}
_items = [items copy];

// Determine new selected item, defaulting to nil.
UITabBarItem *newSelectedItem = nil;
if (self.selectedItem && [self.items containsObject:self.selectedItem]) {
// Previously-selected item still around: Preserve selection.
newSelectedItem = self.selectedItem;
}

self.selectedItem = newSelectedItem;
}

- (void)setSelectedItem:(UITabBarItem *)selectedItem {
if (self.selectedItem == selectedItem) {
return;
}
NSUInteger itemIndex = [self.items indexOfObject:selectedItem];
if (selectedItem && (itemIndex == NSNotFound)) {
NSString *itemTitle = selectedItem.title;
NSString *exceptionMessage =
[NSString stringWithFormat:@"%@ is not a member of the tab bar's `items`.", itemTitle];
[[NSException exceptionWithName:NSInvalidArgumentException reason:exceptionMessage
userInfo:nil] raise];
}

_selectedItem = selectedItem;
}

- (CGSize)intrinsicContentSize {
return CGSizeMake(UIViewNoIntrinsicMetric, kMinHeight);
}
Expand Down
121 changes: 120 additions & 1 deletion components/Tabs2/tests/unit/MDCTabBarViewTests.m
Expand Up @@ -17,12 +17,131 @@
#import "MDCTabBarView.h"

@interface MDCTabBarViewTests : XCTestCase

@property(nonatomic, strong) MDCTabBarView *tabBarView;

@property(nonatomic, strong) UITabBarItem *itemA;

@property(nonatomic, strong) UITabBarItem *itemB;

@property(nonatomic, strong) UITabBarItem *itemC;

@end

@implementation MDCTabBarViewTests

- (void)setUp {
[super setUp];

self.tabBarView = [[MDCTabBarView alloc] init];
self.itemA = [[UITabBarItem alloc] initWithTitle:@"A" image:nil tag:0];
self.itemB = [[UITabBarItem alloc] initWithTitle:@"B" image:nil tag:0];
self.itemC = [[UITabBarItem alloc] initWithTitle:@"C" image:nil tag:0];
}

- (void)tearDown {
self.itemA = nil;
self.itemB = nil;
self.itemC = nil;
self.tabBarView = nil;

[super tearDown];
}

- (void)testInitCreatesObject {
XCTAssertNotNil([[MDCTabBarView alloc] init]);
// When
MDCTabBarView *tabBarView = [[MDCTabBarView alloc] init];

// Then
XCTAssertNotNil(tabBarView);
XCTAssertNotNil(tabBarView.items);
}

/// Tab bars should by default select nil in their items array. The behavior should also be
/// consistent with the UIKit
- (void)testSelectsNilByDefault {
// Given
self.tabBarView.items = @[ self.itemA, self.itemB, self.itemC ];

// Then
XCTAssertNil(self.tabBarView.selectedItem);
}

/// Tab bars should preserve their selection if possible when changing items.
- (void)testPreservesSelectedItem {
// Given items {A, B} which selected item A
self.tabBarView.items = @[ self.itemA, self.itemB ];
self.tabBarView.selectedItem = self.itemA;
XCTAssertEqual(self.tabBarView.selectedItem, self.itemA);

// When
self.tabBarView.items = @[ self.itemC, self.itemA ];

// Then should preserve the selection of A.
XCTAssertEqual(self.tabBarView.selectedItem, self.itemA);
}

/// Tab bars should select nil if the old selection is no longer present.
- (void)testSelectsNilWhenSelectedItemMissing {
// Given items {A, B} which selected item A.
self.tabBarView.items = @[ self.itemA, self.itemB ];
self.tabBarView.selectedItem = self.itemA;
XCTAssertEqual(self.tabBarView.selectedItem, self.itemA);

// When
self.tabBarView.items = @[ self.itemB, self.itemC ];

// Then set items not including A, which should select nil.
XCTAssertNil(self.tabBarView.selectedItem);
}

/// Tab bars should safely accept having their items set to the empty array.
- (void)testSafelyHandlesEmptyItems {
// Given
self.tabBarView.items = @[];
XCTAssertNil(self.tabBarView.selectedItem);

// When
self.tabBarView.items = @[ self.itemA ];
self.tabBarView.items = @[];

// Then
XCTAssertNil(self.tabBarView.selectedItem);
}

// Tab bar should throw error when select the item that doesn't belongs to items.
- (void)testSafelyHandlesNonExistItem {
// Given
self.tabBarView.items = @[];
XCTAssertNil(self.tabBarView.selectedItem);

// When set selected item to nil.
self.tabBarView.selectedItem = nil;

// Then should make no difference to the selection.
XCTAssertNil(self.tabBarView.selectedItem);

// Given items {A, B} which selected item A.
self.tabBarView.items = @[ self.itemA, self.itemB ];
self.tabBarView.selectedItem = self.itemA;
XCTAssertEqual(self.tabBarView.selectedItem, self.itemA);

// When set selected item to C, then should raise exception.
XCTAssertThrows(self.tabBarView.selectedItem = self.itemC);
}

// Setting items to the same set of items should change nothing.
- (void)testItemsUpdateIsIdempotent {
// Given items {A, B} which selected item A.
self.tabBarView.items = @[ self.itemA, self.itemB ];
self.tabBarView.selectedItem = self.itemA;
XCTAssertEqual(self.tabBarView.selectedItem, self.itemA);

// When set same set of items.
self.tabBarView.items = @[ self.itemA, self.itemB ];

// Then should make no difference to the selection.
XCTAssertEqual(self.tabBarView.selectedItem, self.itemA);
}

@end

0 comments on commit 76b14be

Please sign in to comment.