blob: 1729e27ae4cba3ec5f47d7193c7a7fa2d74b3eed [file]
/*
Copyright 2016-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 "UIView+MaterialRTL.h"
#import <objc/runtime.h>
#define MDC_BASE_SDK_EQUAL_OR_ABOVE(x) \
(defined(__IPHONE_##x) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_##x))
static inline UIUserInterfaceLayoutDirection
MDCUserInterfaceLayoutDirectionForSemanticContentAttributeRelativeToLayoutDirection(
UISemanticContentAttribute semanticContentAttribute,
UIUserInterfaceLayoutDirection userInterfaceLayoutDirection) {
switch (semanticContentAttribute) {
case UISemanticContentAttributeUnspecified:
return userInterfaceLayoutDirection;
case UISemanticContentAttributePlayback:
case UISemanticContentAttributeSpatial:
case UISemanticContentAttributeForceLeftToRight:
return UIUserInterfaceLayoutDirectionLeftToRight;
case UISemanticContentAttributeForceRightToLeft:
return UIUserInterfaceLayoutDirectionRightToLeft;
}
NSCAssert(NO, @"Invalid enumeration value %i.", (int)semanticContentAttribute);
return userInterfaceLayoutDirection;
}
@interface UIView (MaterialRTLPrivate)
// On iOS 9 and above, mdc_semanticContentAttribute is backed by UIKit's semanticContentAttribute.
// On iOS 8 and below, mdc_semanticContentAttribute is backed by an associated object.
@property(nonatomic, setter=mdc_setAssociatedSemanticContentAttribute:)
UISemanticContentAttribute mdc_associatedSemanticContentAttribute;
@end
@implementation UIView (MaterialRTL)
- (UISemanticContentAttribute)mdc_semanticContentAttribute {
#if MDC_BASE_SDK_EQUAL_OR_ABOVE(9_0)
if ([self respondsToSelector:@selector(semanticContentAttribute)]) {
return self.semanticContentAttribute;
} else
#endif // MDC_BASE_SDK_EQUAL_OR_ABOVE(9_0)
{
return self.mdc_associatedSemanticContentAttribute;
}
}
- (void)mdc_setSemanticContentAttribute:(UISemanticContentAttribute)semanticContentAttribute {
#if MDC_BASE_SDK_EQUAL_OR_ABOVE(9_0)
if ([self respondsToSelector:@selector(semanticContentAttribute)]) {
self.semanticContentAttribute = semanticContentAttribute;
} else
#endif // MDC_BASE_SDK_EQUAL_OR_ABOVE(9_0)
{
self.mdc_associatedSemanticContentAttribute = semanticContentAttribute;
}
// Invalidate the layout.
[self setNeedsLayout];
}
- (UIUserInterfaceLayoutDirection)mdc_effectiveUserInterfaceLayoutDirection {
#if MDC_BASE_SDK_EQUAL_OR_ABOVE(10_0)
if ([self respondsToSelector:@selector(effectiveUserInterfaceLayoutDirection)]) {
return self.effectiveUserInterfaceLayoutDirection;
} else {
return [UIView mdc_userInterfaceLayoutDirectionForSemanticContentAttribute:
self.mdc_semanticContentAttribute];
}
#else
return [UIView mdc_userInterfaceLayoutDirectionForSemanticContentAttribute:
self.mdc_semanticContentAttribute];
#endif // MDC_BASE_SDK_EQUAL_OR_ABOVE(10_0)
}
+ (UIUserInterfaceLayoutDirection)mdc_userInterfaceLayoutDirectionForSemanticContentAttribute:
(UISemanticContentAttribute)attribute {
#if MDC_BASE_SDK_EQUAL_OR_ABOVE(9_0)
if ([self
respondsToSelector:@selector(userInterfaceLayoutDirectionForSemanticContentAttribute:)]) {
return [self userInterfaceLayoutDirectionForSemanticContentAttribute:attribute];
} else
#endif // MDC_BASE_SDK_EQUAL_OR_ABOVE(9_0)
{
// Use a default of Left-to-Right, as UIKit in iOS 8 and below doesn't support native RTL
// layout.
UIUserInterfaceLayoutDirection applicationLayoutDirection =
UIUserInterfaceLayoutDirectionLeftToRight;
return [self
mdc_userInterfaceLayoutDirectionForSemanticContentAttribute:attribute
relativeToLayoutDirection:applicationLayoutDirection];
}
}
+ (UIUserInterfaceLayoutDirection)
mdc_userInterfaceLayoutDirectionForSemanticContentAttribute:
(UISemanticContentAttribute)semanticContentAttribute
relativeToLayoutDirection:
(UIUserInterfaceLayoutDirection)layoutDirection {
#if MDC_BASE_SDK_EQUAL_OR_ABOVE(10_0)
if ([self
respondsToSelector:@selector(userInterfaceLayoutDirectionForSemanticContentAttribute:
relativeToLayoutDirection:)]) {
return [self userInterfaceLayoutDirectionForSemanticContentAttribute:semanticContentAttribute
relativeToLayoutDirection:layoutDirection];
} else {
return MDCUserInterfaceLayoutDirectionForSemanticContentAttributeRelativeToLayoutDirection(
semanticContentAttribute, layoutDirection);
}
#else
return MDCUserInterfaceLayoutDirectionForSemanticContentAttributeRelativeToLayoutDirection(
semanticContentAttribute, layoutDirection);
#endif // MDC_BASE_SDK_EQUAL_OR_ABOVE(10_0)
}
@end
@implementation UIView (MaterialRTLPrivate)
- (UISemanticContentAttribute)mdc_associatedSemanticContentAttribute {
NSNumber *semanticContentAttributeNumber =
objc_getAssociatedObject(self, @selector(mdc_semanticContentAttribute));
if (semanticContentAttributeNumber) {
return [semanticContentAttributeNumber integerValue];
}
return UISemanticContentAttributeUnspecified;
}
- (void)mdc_setAssociatedSemanticContentAttribute:
(UISemanticContentAttribute)semanticContentAttribute {
objc_setAssociatedObject(self, @selector(mdc_semanticContentAttribute),
@(semanticContentAttribute), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end