blob: 6de387e804987cea73f88cee62e8b9197b962c20 [file]
/*
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 "MDCMultilineTextField.h"
#import "MDCIntrinsicHeightTextView.h"
#import "MDCTextField.h"
#import "MDCTextFieldPositioningDelegate.h"
#import "MDCTextInputBorderView.h"
#import "MDCTextInputCharacterCounter.h"
#import "MDCTextInputController.h"
#import "MDCTextInputUnderlineView.h"
#import "private/MDCTextInputCommonFundament.h"
#import "MaterialMath.h"
#import "MaterialTypography.h"
static NSString *const MDCMultilineTextFieldCursorColorKey = @"MDCMultilineTextFieldCursorColorKey";
static NSString *const MDCMultilineTextFieldExpandsOnOverflowKey =
@"MDCMultilineTextFieldExpandsOnOverflowKey";
static NSString *const MDCMultilineTextFieldFundamentKey = @"MDCMultilineTextFieldFundamentKey";
static NSString *const MDCMultilineTextFieldLayoutDelegateKey =
@"MDCMultilineTextFieldLayoutDelegateKey";
static NSString *const MDCMultilineTextFieldMinimumLinesKey = @"MDCMultilineTextMinimumLinesKey";
static NSString *const MDCMultilineTextFieldMultilineDelegateKey =
@"MDCMultilineTextFieldMultilineDelegateKey";
static NSString *const MDCMultilineTextFieldTextViewKey = @"MDCMultilineTextFieldTextViewKey";
static NSString *const MDCMultilineTextFieldTrailingViewKey =
@"MDCMultilineTextFieldTrailingViewKey";
static NSString *const MDCMultilineTextFieldTrailingViewModeKey =
@"MDCMultilineTextFieldTrailingViewModeKey";
@interface MDCMultilineTextField () {
UIColor *_cursorColor;
MDCIntrinsicHeightTextView *_textView;
}
@property(nonatomic, assign, getter=isEditing) BOOL editing;
@property(nonatomic, assign) CGFloat textViewWidth;
@property(nonatomic, strong) MDCTextInputCommonFundament *fundament;
@property(nonatomic, strong) NSLayoutConstraint *textViewBottomSuperviewBottom;
@property(nonatomic, strong) NSLayoutConstraint *textViewLeading;
@property(nonatomic, strong) NSLayoutConstraint *textViewMinHeight;
@property(nonatomic, strong) NSLayoutConstraint *textViewTop;
@property(nonatomic, strong) NSLayoutConstraint *textViewTrailing;
// textViewTrailingTrailingViewLeading is a constraint from .textView's trailing edge to
// .trailingView's leading edge.
@property(nonatomic, strong) NSLayoutConstraint *textViewTrailingTrailingViewLeading;
@property(nonatomic, strong) NSLayoutConstraint *trailingViewCenterY;
@property(nonatomic, strong) NSLayoutConstraint *trailingViewTrailing;
@end
@implementation MDCMultilineTextField
@synthesize expandsOnOverflow = _expandsOnOverflow;
@synthesize minimumLines = _minimumLines;
@synthesize trailingView = _trailingView;
@synthesize trailingViewMode = _trailingViewMode;
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
_textView = [[MDCIntrinsicHeightTextView alloc] initWithFrame:CGRectZero];
[self setupTextView];
_fundament = [[MDCTextInputCommonFundament alloc] initWithTextInput:self];
[self commonMDCMultilineTextFieldInitialization];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
if ([aDecoder containsValueForKey:MDCMultilineTextFieldTextViewKey]) {
_textView = [aDecoder decodeObjectForKey:MDCMultilineTextFieldTextViewKey];
}
if (!_textView) {
_textView = [[MDCIntrinsicHeightTextView alloc] initWithFrame:CGRectZero];
}
// It should be noted that setupTextView sets many properties of the textView that may have
// been encoded differently.
[self setupTextView];
MDCTextInputCommonFundament *fundament =
[aDecoder decodeObjectForKey:MDCMultilineTextFieldFundamentKey];
_fundament =
fundament ? fundament : [[MDCTextInputCommonFundament alloc] initWithTextInput:self];
[self commonMDCMultilineTextFieldInitialization];
_cursorColor = [aDecoder decodeObjectForKey:MDCMultilineTextFieldCursorColorKey];
if ([aDecoder containsValueForKey:MDCMultilineTextFieldExpandsOnOverflowKey]) {
self.expandsOnOverflow =
[aDecoder decodeBoolForKey:MDCMultilineTextFieldExpandsOnOverflowKey];
}
_layoutDelegate = [aDecoder decodeObjectForKey:MDCMultilineTextFieldLayoutDelegateKey];
if ([aDecoder containsValueForKey:MDCMultilineTextFieldMinimumLinesKey]) {
_minimumLines = [aDecoder decodeIntegerForKey:MDCMultilineTextFieldMinimumLinesKey];
}
_multilineDelegate = [aDecoder decodeObjectForKey:MDCMultilineTextFieldMultilineDelegateKey];
_trailingView = [aDecoder decodeObjectForKey:MDCMultilineTextFieldTrailingViewKey];
_trailingViewMode = (UITextFieldViewMode)
[aDecoder decodeIntegerForKey:MDCMultilineTextFieldTrailingViewModeKey];
}
return self;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[super encodeWithCoder:aCoder];
[aCoder encodeObject:self.cursorColor forKey:MDCMultilineTextFieldCursorColorKey];
[aCoder encodeBool:self.expandsOnOverflow forKey:MDCMultilineTextFieldExpandsOnOverflowKey];
[aCoder encodeObject:self.fundament forKey:MDCMultilineTextFieldFundamentKey];
[aCoder encodeConditionalObject:self.layoutDelegate
forKey:MDCMultilineTextFieldLayoutDelegateKey];
[aCoder encodeInteger:self.minimumLines forKey:MDCMultilineTextFieldMinimumLinesKey];
[aCoder encodeConditionalObject:self.multilineDelegate
forKey:MDCMultilineTextFieldMultilineDelegateKey];
[aCoder encodeObject:self.textView forKey:MDCMultilineTextFieldTextViewKey];
[aCoder encodeObject:self.trailingView forKey:MDCMultilineTextFieldTrailingViewKey];
[aCoder encodeInteger:self.trailingViewMode forKey:MDCMultilineTextFieldTrailingViewModeKey];
}
- (instancetype)copyWithZone:(__unused NSZone *)zone {
MDCMultilineTextField *copy = [[[self class] alloc] initWithFrame:self.frame];
copy.expandsOnOverflow = self.expandsOnOverflow;
copy.cursorColor = self.cursorColor;
// The .fundament creates a .clearButton so setting the clearButton's .tintColor must wait for the
// final .fundament to be created.
copy.fundament = [self.fundament copy];
copy.clearButton.tintColor = self.clearButton.tintColor;
copy.layoutDelegate = self.layoutDelegate;
copy.minimumLines = self.minimumLines;
copy.multilineDelegate = self.multilineDelegate;
copy.placeholder = self.placeholder;
copy.text = self.text;
if ([self.trailingView conformsToProtocol:@protocol(NSCopying)]) {
copy.trailingView = [self.trailingView copy];
}
copy.trailingViewMode = self.trailingViewMode;
return copy;
}
- (void)commonMDCMultilineTextFieldInitialization {
self.backgroundColor = [UIColor clearColor];
self.textColor = _fundament.textColor;
self.font = [UIFont mdc_standardFontForMaterialTextStyle:MDCFontTextStyleBody1];
self.clearButton.tintColor = [UIColor colorWithWhite:0 alpha:[MDCTypography captionFontOpacity]];
_cursorColor = MDCTextInputCursorColor();
[self applyCursorColor];
self.editable = YES;
self.expandsOnOverflow = YES;
_minimumLines = 1;
[self setupUnderlineConstraints];
[self setContentCompressionResistancePriority:UILayoutPriorityDefaultHigh + 1
forAxis:UILayoutConstraintAxisVertical];
}
- (void)subscribeForNotifications {
NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
[defaultCenter addObserver:self
selector:@selector(textViewDidBeginEditing:)
name:UITextViewTextDidBeginEditingNotification
object:self.textView];
[defaultCenter addObserver:self
selector:@selector(textViewDidEndEditing:)
name:UITextViewTextDidEndEditingNotification
object:self.textView];
[defaultCenter addObserver:self
selector:@selector(textViewDidChange:)
name:UITextViewTextDidChangeNotification
object:self.textView];
}
#pragma mark - UIResponder Overrides
- (BOOL)becomeFirstResponder {
return [self.textView becomeFirstResponder];
}
- (BOOL)isFirstResponder {
return self.textView.isFirstResponder;
}
#pragma mark - TextView Implementation
- (void)setupTextView {
[self insertSubview:self.textView atIndex:0];
self.textView.translatesAutoresizingMaskIntoConstraints = NO;
self.textView.scrollEnabled = !_expandsOnOverflow;
[self.textView setContentHuggingPriority:UILayoutPriorityDefaultLow - 1
forAxis:UILayoutConstraintAxisHorizontal];
[self.textView setContentHuggingPriority:UILayoutPriorityDefaultLow - 1
forAxis:UILayoutConstraintAxisVertical];
[self.textView setContentCompressionResistancePriority:UILayoutPriorityDefaultLow - 1
forAxis:UILayoutConstraintAxisHorizontal];
[self.textView setContentCompressionResistancePriority:UILayoutPriorityDefaultHigh + 1
forAxis:UILayoutConstraintAxisVertical];
self.textView.textContainer.lineBreakMode = NSLineBreakByTruncatingTail;
self.textView.textContainer.lineFragmentPadding = 0;
self.textView.textContainerInset = UIEdgeInsetsZero;
[self subscribeForNotifications];
self.textView.backgroundColor = [UIColor clearColor];
self.textView.opaque = NO;
}
#pragma mark - Underline View Implementation
- (void)setupUnderlineConstraints {
if (!self.underline) {
return;
}
NSLayoutConstraint *underlineLeading =
[NSLayoutConstraint constraintWithItem:self.underline
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeLeading
multiplier:1
constant:0];
underlineLeading.priority = UILayoutPriorityDefaultLow;
underlineLeading.active = YES;
NSLayoutConstraint *underlineTrailing =
[NSLayoutConstraint constraintWithItem:self.underline
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTrailing
multiplier:1
constant:0];
underlineTrailing.priority = UILayoutPriorityDefaultLow;
underlineTrailing.active = YES;
NSLayoutConstraint *underlineYTextView =
[NSLayoutConstraint constraintWithItem:self.underline
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.textView
attribute:NSLayoutAttributeBottom
multiplier:1
constant:MDCTextInputHalfPadding];
underlineYTextView.priority = UILayoutPriorityDefaultLow;
underlineYTextView.active = YES;
}
#pragma mark - Layout (UIView)
- (CGSize)intrinsicContentSize {
CGSize boundingSize = CGSizeZero;
boundingSize.width = UIViewNoIntrinsicMetric;
[self.textView layoutIfNeeded];
CGFloat estimatedTextViewHeight =
[self.textView systemLayoutSizeFittingSize:CGSizeMake(CGRectGetWidth(self.textView.bounds), 0)
withHorizontalFittingPriority:UILayoutPriorityDefaultLow
verticalFittingPriority:UILayoutPriorityDefaultLow]
.height;
CGFloat minimumHeight = [self estimatedTextViewLineHeight] * self.minimumLines;
estimatedTextViewHeight = MAX(estimatedTextViewHeight, minimumHeight);
boundingSize.height = [self textInsets].top + estimatedTextViewHeight + [self textInsets].bottom;
return boundingSize;
}
- (CGSize)sizeThatFits:(CGSize)size {
CGSize sizeThatFits = [self intrinsicContentSize];
sizeThatFits.width = size.width;
return sizeThatFits;
}
- (void)layoutSubviews {
[super layoutSubviews];
if (![self.textView isDescendantOfView:self]) {
[self setupTextView];
}
if (self.subviews.firstObject != self.textView) {
[self sendSubviewToBack:self.textView];
}
[self updateTrailingViewAlpha];
[self.fundament layoutSubviewsOfInput];
[self updateBorder];
[self applyCursorColor];
if ([self.positioningDelegate respondsToSelector:@selector(textInputDidLayoutSubviews)]) {
[self.positioningDelegate textInputDidLayoutSubviews];
}
[self updateIntrinsicSizeFromTextView];
}
- (void)updateConstraints {
if (!self.textViewLeading) {
self.textViewLeading = [NSLayoutConstraint constraintWithItem:self.textView
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeLeading
multiplier:1
constant:self.textInsets.left];
self.textViewLeading.priority = UILayoutPriorityDefaultLow;
self.textViewLeading.active = YES;
}
self.textViewLeading.constant = self.textInsets.left;
if (!self.textViewBottomSuperviewBottom) {
self.textViewBottomSuperviewBottom =
[NSLayoutConstraint constraintWithItem:self.textView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationLessThanOrEqual
toItem:self
attribute:NSLayoutAttributeBottom
multiplier:1
constant:-1 * MDCTextInputHalfPadding];
self.textViewBottomSuperviewBottom.priority = UILayoutPriorityDefaultLow;
self.textViewBottomSuperviewBottom.active = YES;
}
if (!self.textViewTop) {
self.textViewTop = [NSLayoutConstraint constraintWithItem:self.textView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTop
multiplier:1
constant:self.textInsets.top];
self.textViewTop.priority = UILayoutPriorityDefaultLow + 1;
self.textViewTop.active = YES;
}
self.textViewTop.constant = self.textInsets.top;
if (!self.textViewTrailing) {
self.textViewTrailing = [NSLayoutConstraint constraintWithItem:self.textView
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self.clearButton
attribute:NSLayoutAttributeLeading
multiplier:1
constant:-1 * [self textInsets].right];
self.textViewTrailing.priority = UILayoutPriorityDefaultLow;
self.textViewTrailing.active = YES;
}
self.textViewTrailing.constant = -1 * [self textInsets].right;
if (!self.textViewMinHeight) {
self.textViewMinHeight = [NSLayoutConstraint
constraintWithItem:self.textView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationGreaterThanOrEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:[self estimatedTextViewLineHeight] * self.minimumLines];
self.textViewMinHeight.priority = UILayoutPriorityDefaultLow + 1;
}
self.textViewMinHeight.active = YES;
self.textViewMinHeight.constant = [self estimatedTextViewLineHeight] * self.minimumLines;
[self.fundament updateConstraintsOfInput];
[self updateTrailingViewLayout];
[self updateIntrinsicSizeFromTextView];
// This must always be the last message in this method.
[super updateConstraints];
}
+ (BOOL)requiresConstraintBasedLayout {
return YES;
}
- (CGFloat)estimatedTextViewLineHeight {
CGFloat scale = UIScreen.mainScreen.scale;
return MDCCeil(self.textView.font.lineHeight * scale) / scale;
}
- (void)updateIntrinsicSizeFromTextView {
if ([self textViewWidthDidChange]) {
[self invalidateIntrinsicContentSize];
}
}
- (BOOL)textViewWidthDidChange {
BOOL widthDidChange = NO;
CGFloat currentTextViewWidth = CGRectGetWidth(self.textView.bounds);
if (self.textViewWidth != currentTextViewWidth) {
widthDidChange = YES;
}
self.textViewWidth = currentTextViewWidth;
return widthDidChange;
}
#pragma mark - Touch (UIView)
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
UIView *receiver = [super hitTest:point withEvent:event];
// We do this so the hit zone to become first responder is larger than just the small text view.
if (receiver == self && self.isEditing == NO) {
return self.textView;
}
return receiver;
}
#pragma mark - Trailing View Implementation
- (void)updateTrailingViewLayout {
if (!self.trailingView) {
return;
}
self.trailingView.translatesAutoresizingMaskIntoConstraints = NO;
if (![self.trailingView isDescendantOfView:self]) {
[self addSubview:self.trailingView];
}
if (!self.trailingViewTrailing) {
self.trailingViewTrailing = [NSLayoutConstraint constraintWithItem:self.trailingView
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self.clearButton
attribute:NSLayoutAttributeTrailing
multiplier:1
constant:0];
}
self.trailingViewTrailing.active = YES;
if (!self.trailingViewCenterY) {
self.trailingViewCenterY = [NSLayoutConstraint constraintWithItem:self.trailingView
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.clearButton
attribute:NSLayoutAttributeCenterY
multiplier:1
constant:0];
}
self.trailingViewCenterY.active = YES;
if (!self.textViewTrailingTrailingViewLeading) {
self.textViewTrailingTrailingViewLeading =
[NSLayoutConstraint constraintWithItem:self.textView
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self.trailingView
attribute:NSLayoutAttributeLeading
multiplier:1
constant:self.textViewTrailing.constant];
}
self.textViewTrailingTrailingViewLeading.active = !MDCCGFloatEqual([self trailingViewAlpha], 0.f);
}
- (void)updateTrailingViewAlpha {
self.trailingView.alpha = [self trailingViewAlpha];
}
- (CGFloat)trailingViewAlpha {
// The trailing view has the same behavior as .rightView in UITextField: It has visual precedence
// over the clear button.
CGFloat trailingViewAlpha;
switch (self.trailingViewMode) {
case UITextFieldViewModeAlways:
trailingViewAlpha = 1.f;
break;
case UITextFieldViewModeWhileEditing:
trailingViewAlpha = self.isEditing ? 1.f : 0.f;
break;
case UITextFieldViewModeUnlessEditing:
trailingViewAlpha = self.isEditing ? 0.f : 1.f;
break;
case UITextFieldViewModeNever:
trailingViewAlpha = 0.f;
break;
default:
NSAssert(NO, @"Invalid enumeration value %li.", (long)self.trailingViewMode);
trailingViewAlpha = self.trailingViewAlpha;
break;
}
return trailingViewAlpha;
}
#pragma mark - Border Implementation
- (UIBezierPath *)defaultBorderPath {
CGRect borderBound = self.bounds;
borderBound.size.height = self.underline.center.y;
return [UIBezierPath
bezierPathWithRoundedRect:borderBound
byRoundingCorners:UIRectCornerTopLeft | UIRectCornerTopRight
cornerRadii:CGSizeMake(MDCTextInputBorderRadius, MDCTextInputBorderRadius)];
}
- (void)updateBorder {
self.borderView.borderPath = self.borderPath;
}
#pragma mark - Applying Color
- (void)applyCursorColor {
self.textView.tintColor = self.cursorColor;
}
#pragma mark - Properties Implementation
- (NSAttributedString *)attributedPlaceholder {
return self.fundament.attributedPlaceholder;
}
- (void)setAttributedPlaceholder:(NSAttributedString *)attributedPlaceholder {
self.fundament.attributedPlaceholder = attributedPlaceholder;
}
- (NSAttributedString *)attributedText {
return self.textView.attributedText;
}
- (void)setAttributedText:(NSAttributedString *)attributedText {
self.textView.attributedText = attributedText;
[self.fundament didSetText];
[[NSNotificationCenter defaultCenter] postNotificationName:MDCTextFieldTextDidSetTextNotification
object:self];
}
- (UIBezierPath *)borderPath {
return self.fundament.borderPath ? self.fundament.borderPath : [self defaultBorderPath];
}
- (void)setBorderPath:(UIBezierPath *)borderPath {
if (![self.fundament.borderPath isEqual:borderPath]) {
self.fundament.borderPath = borderPath;
[self updateBorder];
}
}
- (MDCTextInputBorderView *)borderView {
return self.fundament.borderView;
}
- (void)setBorderView:(MDCTextInputBorderView *)borderView {
self.fundament.borderView = borderView;
}
- (UIButton *)clearButton {
return self.fundament.clearButton;
}
- (UITextFieldViewMode)clearButtonMode {
return self.fundament.clearButtonMode;
}
- (void)setClearButtonMode:(UITextFieldViewMode)clearButtonMode {
self.fundament.clearButtonMode = clearButtonMode;
}
- (UIColor *)cursorColor {
return _cursorColor ?: MDCTextInputCursorColor();
}
- (void)setCursorColor:(UIColor *)cursorColor {
_cursorColor = cursorColor;
[self applyCursorColor];
}
- (void)setEditable:(BOOL)editable {
[self.textView setEditable:editable];
self.fundament.enabled = editable;
}
- (BOOL)isEnabled {
return self.fundament.isEnabled && self.textView.isEditable;
}
- (void)setEnabled:(BOOL)enabled {
self.fundament.enabled = enabled;
self.textView.editable = enabled;
}
- (void)setExpandsOnOverflow:(BOOL)expandsOnOverflow {
if (_expandsOnOverflow != expandsOnOverflow) {
_expandsOnOverflow = expandsOnOverflow;
self.textView.scrollEnabled = !expandsOnOverflow;
[self setNeedsUpdateConstraints];
}
}
- (UIFont *)font {
if (_textView) {
return _textView.font;
}
return self.textView.font;
}
- (void)setFont:(UIFont *)font {
if (self.textView.font != font) {
[self.textView setFont:font];
[_fundament didSetFont];
}
}
- (BOOL)hidesPlaceholderOnInput {
return self.fundament.hidesPlaceholderOnInput;
}
- (void)setHidesPlaceholderOnInput:(BOOL)hidesPlaceholderOnInput {
self.fundament.hidesPlaceholderOnInput = hidesPlaceholderOnInput;
}
- (UILabel *)leadingUnderlineLabel {
return self.fundament.leadingUnderlineLabel;
}
- (NSUInteger)minimumLines {
if (_minimumLines < 1) {
_minimumLines = 1;
}
return _minimumLines;
}
- (void)setMinimumLines:(NSUInteger)minimumLines {
if (_minimumLines != minimumLines) {
_minimumLines = minimumLines > 0 ? minimumLines : 1;
[self setNeedsUpdateConstraints];
}
}
- (NSString *)placeholder {
return self.fundament.placeholder;
}
- (void)setPlaceholder:(NSString *)placeholder {
[self.fundament setPlaceholder:placeholder];
}
- (UILabel *)placeholderLabel {
return self.fundament.placeholderLabel;
}
- (id<MDCTextInputPositioningDelegate>)positioningDelegate {
return self.fundament.positioningDelegate;
}
- (void)setPositioningDelegate:(id<MDCTextInputPositioningDelegate>)positioningDelegate {
self.fundament.positioningDelegate = positioningDelegate;
}
- (NSString *)text {
return self.textView.text;
}
- (void)setText:(NSString *)text {
[self.textView setText:text];
[self.fundament didSetText];
[[NSNotificationCenter defaultCenter] postNotificationName:MDCTextFieldTextDidSetTextNotification
object:self];
}
- (UIColor *)textColor {
return self.fundament.textColor;
}
- (void)setTextColor:(UIColor *)textColor {
[self.textView setTextColor:textColor];
self.fundament.textColor = textColor;
}
- (UIEdgeInsets)textInsets {
return self.fundament.textInsets;
}
- (MDCTextInputTextInsetsMode)textInsetsMode {
return self.fundament.textInsetsMode;
}
- (void)setTextInsetsMode:(MDCTextInputTextInsetsMode)textInsetsMode {
self.fundament.textInsetsMode = textInsetsMode;
}
- (MDCIntrinsicHeightTextView *)textView {
if (!_textView) {
_textView = [[MDCIntrinsicHeightTextView alloc] initWithFrame:CGRectZero];
[self setupTextView];
[self setupUnderlineConstraints];
}
return _textView;
}
- (void)setTextView:(MDCIntrinsicHeightTextView *)textView {
if (![_textView isEqual:textView]) {
[_textView removeFromSuperview];
_textView = textView;
if (textView) {
[self setupTextView];
[self setupUnderlineConstraints];
}
}
}
- (UILabel *)trailingUnderlineLabel {
return self.fundament.trailingUnderlineLabel;
}
- (void)setTrailingView:(UIView *)trailingView {
if (_trailingView != trailingView) {
[_trailingView removeFromSuperview];
[self addSubview:trailingView];
_trailingView = trailingView;
[self setNeedsUpdateConstraints];
}
}
- (MDCTextInputUnderlineView *)underline {
return self.fundament.underline;
}
#pragma mark - UITextView Notification Observation
- (void)textViewDidBeginEditing:(__unused NSNotification *)note {
self.editing = YES;
[self.fundament didBeginEditing];
}
- (void)textViewDidChange:(__unused NSNotification *)note {
[self.fundament didChange];
CGSize currentSize = self.bounds.size;
CGSize requiredSize = [self sizeThatFits:CGSizeMake(currentSize.width, CGFLOAT_MAX)];
if (currentSize.height != requiredSize.height && self.textView.delegate &&
[self.layoutDelegate
respondsToSelector:@selector(multilineTextField:didChangeContentSize:)]) {
id<MDCMultilineTextInputLayoutDelegate> delegate =
(id<MDCMultilineTextInputLayoutDelegate>)self.layoutDelegate;
[delegate multilineTextField:self didChangeContentSize:requiredSize];
}
}
- (void)textViewDidEndEditing:(__unused NSNotification *)note {
self.editing = NO;
[self.fundament didEndEditing];
}
#pragma mark - Accessibility
- (NSString *)accessibilityValue {
NSString *value = [self.text length] ? self.text : self.placeholder;
if (self.leadingUnderlineLabel.text.length > 0) {
[value stringByAppendingFormat:@"%@ %@", [super accessibilityValue],
self.leadingUnderlineLabel.accessibilityLabel];
}
return value;
}
- (BOOL)mdc_adjustsFontForContentSizeCategory {
return _fundament.mdc_adjustsFontForContentSizeCategory;
}
- (void)mdc_setAdjustsFontForContentSizeCategory:(BOOL)adjusts {
// Prior to iOS 9 RTL was not automatically applied, so we don't need to apply any fixes.
if ([self.textView respondsToSelector:@selector(setAdjustsFontForContentSizeCategory:)]) {
[self.textView setAdjustsFontForContentSizeCategory:adjusts];
}
[_fundament mdc_setAdjustsFontForContentSizeCategory:adjusts];
}
@end