Skip to content

Commit

Permalink
[Tabs] Fork selection indicator. (#7723)
Browse files Browse the repository at this point in the history
Forks the selection indicator classes from Tabs. Alternatives include putting
the indicator into an "extension", which would break our convention of base
components not depending on extensions. Another would be to have the
TabBarView target depend on Tabs, but that makes it harder to ensure a "clean"
set of dependencies.

This PR is a simple copy + rename with no change to implementation.  Tests will be added later as functionality is included into TabBarView.

Part of #7645
  • Loading branch information
Robert Moore committed Jun 27, 2019
1 parent 609d76a commit 2703d00
Show file tree
Hide file tree
Showing 12 changed files with 385 additions and 8 deletions.
5 changes: 2 additions & 3 deletions components/Tabs/src/TabBarView/MDCTabBarItemCustomViewing.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

#import <Foundation/Foundation.h>

#import "MDCTabBarSelectionIndicatorSupporting.h"
#import "MDCTabBarViewIndicatorSupporting.h"

/**
Defines the necessary APIs for MDCTabBarView to use a UITabBarItem for a custom view property.
Expand All @@ -25,7 +25,6 @@
@protocol MDCTabBarItemCustomViewing

/** A custom view to be displayed for a tab bar item. */
@property(nullable, nonatomic, strong)
UIView<MDCTabBarSelectionIndicatorSupporting> *mdc_customView;
@property(nullable, nonatomic, strong) UIView<MDCTabBarViewIndicatorSupporting> *mdc_customView;

@end
23 changes: 23 additions & 0 deletions components/Tabs/src/TabBarView/MDCTabBarViewIndicatorAttributes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2017-present the Material Components for iOS authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#import <UIKit/UIKit.h>

/** Defines how a tab bar indicator should appear in a specific context. */
@interface MDCTabBarViewIndicatorAttributes : NSObject <NSCopying>

/** If non-nil, a path that should be filled with the indicator tint color. */
@property(nonatomic, nullable) UIBezierPath *path;

@end
51 changes: 51 additions & 0 deletions components/Tabs/src/TabBarView/MDCTabBarViewIndicatorAttributes.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright 2017-present the Material Components for iOS authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#import "MDCTabBarViewIndicatorAttributes.h"

@implementation MDCTabBarViewIndicatorAttributes

#pragma mark - NSCopying

- (instancetype)copyWithZone:(__unused NSZone *)zone {
MDCTabBarViewIndicatorAttributes *attributes = [[[self class] alloc] init];
attributes.path = _path;
return attributes;
}

#pragma mark - NSObject

- (NSString *)description {
return [NSString stringWithFormat:@"%@ path:%@", [super description], _path];
}

- (BOOL)isEqual:(id)object {
if (![object isKindOfClass:[self class]]) {
return NO;
}

MDCTabBarViewIndicatorAttributes *otherAttributes = object;

if ((_path != otherAttributes.path) && ![_path isEqual:otherAttributes.path]) {
return NO;
}

return YES;
}

- (NSUInteger)hash {
return _path.hash;
}

@end
39 changes: 39 additions & 0 deletions components/Tabs/src/TabBarView/MDCTabBarViewIndicatorContext.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2017-present the Material Components for iOS authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#import <UIKit/UIKit.h>

/** Information about the context in which a tab bar indicator will be displayed. */
@protocol MDCTabBarViewIndicatorContext <NSObject>

/** The tab bar item for the indicated tab. */
@property(nonatomic, readonly, nonnull) UITabBarItem *item;

/**
The full bounds of the tab's view.
Any paths should be created relative to this coordinate space.
*/
@property(nonatomic, readonly) CGRect bounds;

/**
The frame for the tab's primary content in its coordinate space.
For title-only tabs, this is the frame of the title text.
For image-only tabs, this is the frame of the primary image.
For title-and-image tabs, it is the union of the title and primary image's frames.
*/
@property(nonatomic, readonly) CGRect contentFrame;

@end
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@

/**
A simple protocol that indicates the responder can be targeted by an
@c MDCTabBarSelectionIndicatorTemplate.
@c MDCTabBarViewIndicatorTemplate.
@seealso MDCTabBarIndicatorTemplate
@seealso MDCTabBarViewIndicatorTemplate
*/
@protocol MDCTabBarSelectionIndicatorSupporting
@protocol MDCTabBarViewIndicatorSupporting

/**
The bounds of the receiver.
Expand Down
34 changes: 34 additions & 0 deletions components/Tabs/src/TabBarView/MDCTabBarViewIndicatorTemplate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright 2017-present the Material Components for iOS authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#import <UIKit/UIKit.h>

@class MDCTabBarViewIndicatorAttributes;
@protocol MDCTabBarViewIndicatorContext;

/*
Template for indicator content which defines how the indicator changes appearance in response to
changes in its context.
Template objects are expected to be immutable once set on a tab bar.
*/
@protocol MDCTabBarViewIndicatorTemplate <NSObject>

/**
Returns an attributes object that describes how the indicator should appear in a given context.
*/
- (nonnull MDCTabBarViewIndicatorAttributes *)indicatorAttributesForContext:
(nonnull id<MDCTabBarViewIndicatorContext>)context;

@end
2 changes: 1 addition & 1 deletion components/Tabs/src/TabBarView/MaterialTabs+TabBarView.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@

#import "MDCTabBarItem.h"
#import "MDCTabBarItemCustomViewing.h"
#import "MDCTabBarSelectionIndicatorSupporting.h"
#import "MDCTabBarView.h"
#import "MDCTabBarViewIndicatorSupporting.h"
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright 2017-present the Material Components for iOS authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#import <UIKit/UIKit.h>

@class MDCTabBarViewIndicatorAttributes;

/** View responsible for drawing the indicator behind tab content and animating changes. */
@interface MDCTabBarViewIndicatorView : UIView

/**
Called to indicate that the indicator should update to display new attributes. This method may be
called from an implicit animation block.
*/
- (void)applySelectionIndicatorAttributes:(MDCTabBarViewIndicatorAttributes *)attributes;

@end
105 changes: 105 additions & 0 deletions components/Tabs/src/TabBarView/private/MDCTabBarViewIndicatorView.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// Copyright 2017-present the Material Components for iOS authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#import "MDCTabBarViewIndicatorView.h"

#import "MDCTabBarViewIndicatorAttributes.h"

/** Content view that displays a filled path and supports animation between states. */
@interface MDCTabBarViewIndicatorShapeView : UIView

/** The path to display. It will be filled using the view's tintColor. */
@property(nonatomic, nullable) UIBezierPath *path;

@end

@implementation MDCTabBarViewIndicatorView {
/// View responsible for drawing the indicator's path.
MDCTabBarViewIndicatorShapeView *_shapeView;
}

- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self commonMDCTabBarViewIndicatorViewInit];
}
return self;
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
[self commonMDCTabBarViewIndicatorViewInit];
}
return self;
}

#pragma mark - Public

- (void)applySelectionIndicatorAttributes:(MDCTabBarViewIndicatorAttributes *)attributes {
_shapeView.path = attributes.path;
}

#pragma mark - Private

- (void)commonMDCTabBarViewIndicatorViewInit {
// Fill the indicator with the shape.
_shapeView = [[MDCTabBarViewIndicatorShapeView alloc] initWithFrame:self.bounds];
_shapeView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self addSubview:_shapeView];
}

@end

#pragma mark -

@implementation MDCTabBarViewIndicatorShapeView

- (UIBezierPath *)path {
CAShapeLayer *shapeLayer = (CAShapeLayer *)self.layer;
CGPathRef cgPath = shapeLayer.path;
return cgPath ? [UIBezierPath bezierPathWithCGPath:cgPath] : nil;
}

- (void)setPath:(UIBezierPath *)path {
CAShapeLayer *shapeLayer = (CAShapeLayer *)self.layer;
shapeLayer.path = path.CGPath;
}

#pragma mark - CALayerDelegate

- (id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event {
id<CAAction> action = [super actionForLayer:layer forKey:event];
// Support implicit animation of paths.
if ((!action || action == [NSNull null]) && (layer == self.layer) && [event isEqual:@"path"]) {
return [CABasicAnimation animationWithKeyPath:event];
}
return action;
}

#pragma mark - UIView

+ (Class)layerClass {
return [CAShapeLayer class];
}

- (void)tintColorDidChange {
[super tintColorDidChange];

// Update layer fill color
CAShapeLayer *shapeLayer = (CAShapeLayer *)self.layer;
shapeLayer.fillColor = self.tintColor.CGColor;
}

@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright 2017-present the Material Components for iOS authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#import <UIKit/UIKit.h>

#import "MDCTabBarViewIndicatorContext.h"

/// Concrete implementation of a tab indicator context.
@interface MDCTabBarViewPrivateIndicatorContext : NSObject <MDCTabBarViewIndicatorContext>

- (null_unspecified instancetype)init NS_UNAVAILABLE;

/// Designated initializer which creates a context from members.
- (nonnull instancetype)initWithItem:(nonnull UITabBarItem *)item
bounds:(CGRect)bounds
contentFrame:(CGRect)contentFrame NS_DESIGNATED_INITIALIZER;

@end

0 comments on commit 2703d00

Please sign in to comment.