diff --git a/components/TextFields/src/ContainedInputView/MDCBaseTextField.m b/components/TextFields/src/ContainedInputView/MDCBaseTextField.m index b9320c41e4a..d49d2091cc7 100644 --- a/components/TextFields/src/ContainedInputView/MDCBaseTextField.m +++ b/components/TextFields/src/ContainedInputView/MDCBaseTextField.m @@ -23,9 +23,10 @@ #import "private/MDCContainedInputViewColorViewModel.h" #import "private/MDCContainedInputViewLabelAnimation.h" #import "private/MDCContainedInputViewLabelState.h" +#import "private/MDCContainedInputViewStyleBase.h" #import "private/MDCContainedInputViewVerticalPositioningGuideBase.h" -@interface MDCBaseTextField () +@interface MDCBaseTextField () @property(strong, nonatomic) UILabel *label; @property(strong, nonatomic) MDCBaseTextFieldLayout *layout; @@ -43,6 +44,7 @@ @interface MDCBaseTextField () @end @implementation MDCBaseTextField +@synthesize containerStyle = _containerStyle; #pragma mark Object Lifecycle @@ -74,6 +76,7 @@ - (void)initializeProperties { self.labelBehavior = MDCTextControlLabelBehaviorFloats; self.layoutDirection = self.mdf_effectiveUserInterfaceLayoutDirection; self.labelState = [self determineCurrentLabelState]; + self.containerStyle = [[MDCContainedInputViewStyleBase alloc] init]; self.colorViewModels = [[NSMutableDictionary alloc] init]; } @@ -195,7 +198,7 @@ - (MDCBaseTextFieldLayout *)calculateLayoutWithTextFieldSize:(CGSize)textFieldSi } - (id)createPositioningReference { - return [[MDCContainedInputViewVerticalPositioningGuideBase alloc] init]; + return [self.containerStyle positioningReference]; } - (CGFloat)clearButtonSideLengthWithTextFieldSize:(CGSize)textFieldSize { @@ -339,6 +342,17 @@ - (void)setLayoutDirection:(UIUserInterfaceLayoutDirection)layoutDirection { [self setNeedsLayout]; } +#pragma mark MDCContainedInputView accessors + +- (void)setContainerStyle:(id)containerStyle { + id oldStyle = _containerStyle; + if (oldStyle) { + [oldStyle removeStyleFrom:self]; + } + _containerStyle = containerStyle; + [_containerStyle applyStyleToContainedInputView:self]; +} + #pragma mark UITextField Layout Overrides // The implementations for this method and the method below deserve some context! Unfortunately, diff --git a/components/TextFields/src/ContainedInputView/private/MDCContainedInputView.h b/components/TextFields/src/ContainedInputView/private/MDCContainedInputView.h new file mode 100644 index 00000000000..00c529c49f9 --- /dev/null +++ b/components/TextFields/src/ContainedInputView/private/MDCContainedInputView.h @@ -0,0 +1,113 @@ +// Copyright 2019-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 +#import + +#import "MDCContainedInputViewColorViewModel.h" +#import "MDCContainedInputViewLabelAnimation.h" +#import "MDCContainedInputViewLabelState.h" +#import "MDCContainerStyleVerticalPositioningReference.h" +#import "MDCTextControlLabelBehavior.h" +#import "MDCTextControlState.h" + +static const CGFloat kMDCContainedInputViewDefaultAnimationDuration = (CGFloat)0.15; + +@protocol MDCContainedInputViewStyle; + +@protocol MDCContainedInputView + +/** + This object represents the style of the text control, i.e. the thing that makes it filled or + outlined. See the documentation for MDCContainedInputViewStyle for more information on its + responsibilities. + */ +@property(nonatomic, strong, nonnull) id containerStyle; + +/** + Describes the current @c MDCtextControlState of the view. This value is affected by things like + UIControlState, as well as whether or not it's editing. + */ +@property(nonatomic, assign, readonly) MDCTextControlState textControlState; + +/** + Describes the current MDCContainedInputViewLabelState of the contained input view. This + value is affected by things like the view's @c textControlState, its @c labelBehavior, and the + text of the floating label. + */ +@property(nonatomic, assign, readonly) MDCContainedInputViewLabelState labelState; + +/** + Describes the behavior of the label when the view begins editing. + */ +@property(nonatomic, assign, readonly) MDCTextControlLabelBehavior labelBehavior; + +/** + The @c label is a label that occupies the text area in a resting state with no text and that either + floats above the text or disappears in an editing state. It is distinct from a placeholder. + */ +@property(strong, nonatomic, readonly, nonnull) UILabel *label; + +/** + The @c normalFont is the contained input view's primary font. The text has this font. The label + also has this font when it isn't floating. + */ +@property(strong, nonatomic, readonly, nonnull) UIFont *normalFont; + +/** + The @c floatingFont is the font of the label when it's floating. + */ +@property(strong, nonatomic, readonly, nonnull) UIFont *floatingFont; + +/** + This method returns a MDCContainedInputViewColorViewModel for a given MDCTextControlState. + */ +- (nonnull MDCContainedInputViewColorViewModel *)containedInputViewColorViewModelForState: + (MDCTextControlState)textControlState; + +/** + This method sets a MDCContainedInputViewColorViewModel for a given MDCTextControlState. + */ +- (void)setContainedInputViewColorViewModel: + (nonnull MDCContainedInputViewColorViewModel *)containedInputViewColorViewModel + forState:(MDCTextControlState)textFieldState; + +@end + +@protocol MDCContainedInputViewStyle + +/** + This method allows objects conforming to MDCContainedInputViewStyle to apply themselves to objects + conforming to MDCContainedInputView. + */ +- (void)applyStyleToContainedInputView:(nonnull id)containedInputView; +/** + This method allows objects conforming to MDCContainedInputViewStyle to remove the styling + previously applied to objects conforming to MDCContainedInputView. + */ +- (void)removeStyleFrom:(nonnull id)containedInputView; + +/** + The method returns a UIFont for the floating label based on the @c normalFont of the + view. + */ +- (UIFont *_Nonnull)floatingFontWithNormalFont:(nonnull UIFont *)font; + +/** + This method returns an object that tells the view where to position it's views + vertically. + */ +- (nonnull id)positioningReference; + +@end diff --git a/components/TextFields/src/ContainedInputView/private/MDCContainedInputViewLabelAnimation.m b/components/TextFields/src/ContainedInputView/private/MDCContainedInputViewLabelAnimation.m index 7eb59867708..e0893bc42d2 100644 --- a/components/TextFields/src/ContainedInputView/private/MDCContainedInputViewLabelAnimation.m +++ b/components/TextFields/src/ContainedInputView/private/MDCContainedInputViewLabelAnimation.m @@ -14,10 +14,9 @@ #import "MDCContainedInputViewLabelAnimation.h" +#import "MDCContainedInputView.h" #import "MaterialAnimationTiming.h" -static const CGFloat kDefaultAnimationDuration = (CGFloat)0.15; - @implementation MDCContainedInputViewLabelAnimation + (void)layOutLabel:(nonnull UILabel *)label @@ -47,7 +46,7 @@ + (void)layOutLabel:(nonnull UILabel *)label CAMediaTimingFunction *timingFunction = [CAMediaTimingFunction mdc_functionWithType:MDCAnimationTimingFunctionStandard]; [UIView mdc_animateWithTimingFunction:timingFunction - duration:kDefaultAnimationDuration + duration:kMDCContainedInputViewDefaultAnimationDuration delay:0 options:0 animations:^{ diff --git a/components/TextFields/src/ContainedInputView/private/MDCContainedInputViewStyleBase.h b/components/TextFields/src/ContainedInputView/private/MDCContainedInputViewStyleBase.h new file mode 100644 index 00000000000..ec1f1632fc9 --- /dev/null +++ b/components/TextFields/src/ContainedInputView/private/MDCContainedInputViewStyleBase.h @@ -0,0 +1,25 @@ +// Copyright 2019-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 +#import + +#import "MDCContainedInputView.h" + +/** + A base implementation of MDCContainedInputViewStyle. This is only used for base text controls, i.e. + ones that are not filled or outlined. + */ +@interface MDCContainedInputViewStyleBase : NSObject +@end diff --git a/components/TextFields/src/ContainedInputView/private/MDCContainedInputViewStyleBase.m b/components/TextFields/src/ContainedInputView/private/MDCContainedInputViewStyleBase.m new file mode 100644 index 00000000000..667c8c1e7ca --- /dev/null +++ b/components/TextFields/src/ContainedInputView/private/MDCContainedInputViewStyleBase.m @@ -0,0 +1,43 @@ +// Copyright 2019-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 "MDCContainedInputViewStyleBase.h" + +#import +#import + +#import "MDCContainedInputView.h" +#import "MDCContainedInputViewVerticalPositioningGuideBase.h" + +static const CGFloat kBaseFloatingLabelScaleFactor = 0.75; + +@implementation MDCContainedInputViewStyleBase + +- (UIFont *)floatingFontWithNormalFont:(UIFont *)font { + CGFloat scaleFactor = kBaseFloatingLabelScaleFactor; + CGFloat floatingFontSize = font.pointSize * scaleFactor; + return [font fontWithSize:floatingFontSize]; +} + +- (void)applyStyleToContainedInputView:(id)inputView { +} + +- (void)removeStyleFrom:(id)containedInputView { +} + +- (id)positioningReference { + return [[MDCContainedInputViewVerticalPositioningGuideBase alloc] init]; +} + +@end diff --git a/components/TextFields/tests/snapshot/MDCBaseTextFieldSnapshotTests.m b/components/TextFields/tests/snapshot/MDCBaseTextFieldSnapshotTests.m index 837865e9ad7..c5d5c9c006a 100644 --- a/components/TextFields/tests/snapshot/MDCBaseTextFieldSnapshotTests.m +++ b/components/TextFields/tests/snapshot/MDCBaseTextFieldSnapshotTests.m @@ -23,6 +23,7 @@ @interface MDCBaseTextFieldTestsSnapshotTests : MDCSnapshotTestCase @property(strong, nonatomic) MDCBaseTextField *textField; +@property(nonatomic, assign) BOOL areAnimationsEnabled; @end @implementation MDCBaseTextFieldTestsSnapshotTests @@ -30,6 +31,8 @@ @implementation MDCBaseTextFieldTestsSnapshotTests - (void)setUp { [super setUp]; + self.areAnimationsEnabled = UIView.areAnimationsEnabled; + [UIView setAnimationsEnabled:NO]; self.textField = [self createBaseTextFieldInKeyWindow]; // Uncomment below to recreate all the goldens (or add the following line to the specific // test you wish to recreate the golden for). @@ -40,6 +43,7 @@ - (void)tearDown { [super tearDown]; [self.textField removeFromSuperview]; self.textField = nil; + [UIView setAnimationsEnabled:self.areAnimationsEnabled]; } - (MDCBaseTextField *)createBaseTextFieldInKeyWindow { @@ -53,7 +57,6 @@ - (MDCBaseTextField *)createBaseTextFieldInKeyWindow { - (void)validateTextField:(MDCBaseTextField *)textField { XCTestExpectation *expectation = [[XCTestExpectation alloc] initWithDescription:@"textfield_validation_expectation"]; - dispatch_after( dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kTextFieldValidationEstimatedAnimationDuration * NSEC_PER_SEC)),