提交
This commit is contained in:
291
TUIKit/TIMCommon/CommonModel/TIMRTLUtil.m
Normal file
291
TUIKit/TIMCommon/CommonModel/TIMRTLUtil.m
Normal file
@@ -0,0 +1,291 @@
|
||||
//
|
||||
// TIMRTLUtil.m
|
||||
// TIMCommon
|
||||
//
|
||||
// Created by cologne on 2023/7/21.
|
||||
// Copyright © 2023 Tencent. All rights reserved
|
||||
//
|
||||
|
||||
#import "TIMRTLUtil.h"
|
||||
#import <objc/runtime.h>
|
||||
#import <TUICore/TUIGlobalization.h>
|
||||
|
||||
@implementation TIMRTLUtil
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface UIView (TUIRTL)
|
||||
|
||||
@end
|
||||
@implementation UIView (TUIRTL)
|
||||
- (void)setRTLFrame:(CGRect)frame width:(CGFloat)width {
|
||||
if (isRTL()) {
|
||||
if (self.superview == nil) {
|
||||
NSAssert(0, @"must invoke after have superView");
|
||||
}
|
||||
CGFloat x = width - frame.origin.x - frame.size.width;
|
||||
frame.origin.x = x;
|
||||
}
|
||||
self.frame = frame;
|
||||
}
|
||||
|
||||
- (void)setRTLFrame:(CGRect)frame {
|
||||
[self setRTLFrame:frame width:self.superview.frame.size.width];
|
||||
}
|
||||
|
||||
- (void)resetFrameToFitRTL {
|
||||
[self setRTLFrame:self.frame];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface UIImage (TUIRTL)
|
||||
|
||||
@end
|
||||
@implementation UIImage (TUIRTL)
|
||||
- (UIImage *_Nonnull)checkOverturn{
|
||||
if (isRTL()) {
|
||||
UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale);
|
||||
CGContextRef bitmap = UIGraphicsGetCurrentContext();
|
||||
CGContextTranslateCTM(bitmap, self.size.width / 2, self.size.height / 2);
|
||||
CGContextScaleCTM(bitmap, -1.0, -1.0);
|
||||
CGContextTranslateCTM(bitmap, -self.size.width / 2, -self.size.height / 2);
|
||||
CGContextDrawImage(bitmap, CGRectMake(0, 0, self.size.width, self.size.height), self.CGImage);
|
||||
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
return image;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (UIImage *)_imageFlippedForRightToLeftLayoutDirection {
|
||||
if (isRTL()) {
|
||||
return [UIImage imageWithCGImage:self.CGImage
|
||||
scale:self.scale
|
||||
orientation:UIImageOrientationUpMirrored];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (UIImage *)rtl_imageFlippedForRightToLeftLayoutDirection {
|
||||
if (isRTL()) {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
UITraitCollection *const scaleTraitCollection = [UITraitCollection currentTraitCollection];
|
||||
UITraitCollection *const darkUnscaledTraitCollection = [UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleDark];
|
||||
UITraitCollection *const darkScaledTraitCollection =
|
||||
[UITraitCollection traitCollectionWithTraitsFromCollections:@[ scaleTraitCollection, darkUnscaledTraitCollection ]];
|
||||
|
||||
UIImage *lightImg = [[self.imageAsset imageWithTraitCollection:[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleLight]]
|
||||
_imageFlippedForRightToLeftLayoutDirection];
|
||||
|
||||
UIImage *darkImage = [[self.imageAsset imageWithTraitCollection:[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleDark]]
|
||||
_imageFlippedForRightToLeftLayoutDirection];
|
||||
|
||||
UIImage *image =
|
||||
[lightImg imageWithConfiguration:[self.configuration
|
||||
configurationWithTraitCollection:[UITraitCollection
|
||||
traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleLight]]];
|
||||
[image.imageAsset registerImage:darkImage withTraitCollection:darkScaledTraitCollection];
|
||||
return image;
|
||||
} else {
|
||||
return [UIImage imageWithCGImage:self.CGImage scale:self.scale orientation:UIImageOrientationUpMirrored];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
@interface UINavigationController (TUIRTL)
|
||||
@end
|
||||
@implementation UINavigationController (TUIRTL)
|
||||
+ (void)load {
|
||||
Method oldMethod = class_getInstanceMethod(self, @selector(initWithRootViewController:));
|
||||
Method newMethod = class_getInstanceMethod(self, @selector(rtl_initWithRootViewController:));
|
||||
method_exchangeImplementations(oldMethod, newMethod);
|
||||
}
|
||||
|
||||
- (instancetype)rtl_initWithRootViewController:(UIViewController *)rootViewController {
|
||||
if ([self rtl_initWithRootViewController:rootViewController]) {
|
||||
if (@available(iOS 9.0, *)) {
|
||||
if (isRTL()) {
|
||||
self.navigationBar.semanticContentAttribute = [UIView appearance].semanticContentAttribute;
|
||||
self.view.semanticContentAttribute = [UIView appearance].semanticContentAttribute;
|
||||
}
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
UIEdgeInsets rtlEdgeInsetsWithInsets(UIEdgeInsets insets) {
|
||||
if (insets.left != insets.right && isRTL()) {
|
||||
CGFloat temp = insets.left;
|
||||
insets.left = insets.right;
|
||||
insets.right = temp;
|
||||
}
|
||||
return insets;
|
||||
|
||||
}
|
||||
|
||||
@implementation UIButton (TUIRTL)
|
||||
|
||||
void swizzleInstanceMethod(Class cls, SEL originSelector, SEL swizzleSelector){
|
||||
if (!cls) {
|
||||
return;
|
||||
}
|
||||
/* if current class not exist selector, then get super*/
|
||||
Method originalMethod = class_getInstanceMethod(cls, originSelector);
|
||||
Method swizzledMethod = class_getInstanceMethod(cls, swizzleSelector);
|
||||
|
||||
/* add selector if not exist, implement append with method */
|
||||
if (class_addMethod(cls,
|
||||
originSelector,
|
||||
method_getImplementation(swizzledMethod),
|
||||
method_getTypeEncoding(swizzledMethod)) ) {
|
||||
/* replace class instance method, added if selector not exist */
|
||||
/* for class cluster , it always add new selector here */
|
||||
class_replaceMethod(cls,
|
||||
swizzleSelector,
|
||||
method_getImplementation(originalMethod),
|
||||
method_getTypeEncoding(originalMethod));
|
||||
|
||||
} else {
|
||||
/* swizzleMethod maybe belong to super */
|
||||
class_replaceMethod(cls,
|
||||
swizzleSelector,
|
||||
class_replaceMethod(cls,
|
||||
originSelector,
|
||||
method_getImplementation(swizzledMethod),
|
||||
method_getTypeEncoding(swizzledMethod)),
|
||||
method_getTypeEncoding(originalMethod));
|
||||
}
|
||||
}
|
||||
+ (void)load
|
||||
{
|
||||
swizzleInstanceMethod(self, @selector(setContentEdgeInsets:), @selector(rtl_setContentEdgeInsets:));
|
||||
swizzleInstanceMethod(self, @selector(setImageEdgeInsets:), @selector(rtl_setImageEdgeInsets:));
|
||||
swizzleInstanceMethod(self, @selector(setTitleEdgeInsets:), @selector(rtl_setTitleEdgeInsets:));
|
||||
}
|
||||
|
||||
- (void)rtl_setContentEdgeInsets:(UIEdgeInsets)contentEdgeInsets {
|
||||
[self rtl_setContentEdgeInsets:rtlEdgeInsetsWithInsets(contentEdgeInsets)];
|
||||
}
|
||||
|
||||
- (void)rtl_setImageEdgeInsets:(UIEdgeInsets)imageEdgeInsets {
|
||||
[self rtl_setImageEdgeInsets:rtlEdgeInsetsWithInsets(imageEdgeInsets)];
|
||||
}
|
||||
|
||||
- (void)rtl_setTitleEdgeInsets:(UIEdgeInsets)titleEdgeInsets {
|
||||
[self rtl_setTitleEdgeInsets:rtlEdgeInsetsWithInsets(titleEdgeInsets)];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation UILabel (TUIRTL)
|
||||
|
||||
- (void)setRtlAlignment:(TUITextRTLAlignment)rtlAlignment {
|
||||
objc_setAssociatedObject(self, @selector(rtlAlignment), @(rtlAlignment), OBJC_ASSOCIATION_ASSIGN);
|
||||
switch (rtlAlignment) {
|
||||
case TUITextRTLAlignmentLeading:
|
||||
self.textAlignment = (isRTL() ? NSTextAlignmentRight : NSTextAlignmentLeft);
|
||||
break;
|
||||
case TUITextRTLAlignmentTrailing:
|
||||
self.textAlignment = (isRTL() ? NSTextAlignmentLeft : NSTextAlignmentRight);
|
||||
break;
|
||||
case TUITextRTLAlignmentCenter:
|
||||
self.textAlignment = NSTextAlignmentCenter;
|
||||
case TUITextRTLAlignmentUndefine:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (TUITextRTLAlignment)rtlAlignment {
|
||||
NSNumber *identifier = objc_getAssociatedObject(self, @selector(rtlAlignment));
|
||||
if (identifier) {
|
||||
return identifier.integerValue;
|
||||
}
|
||||
return TUITextRTLAlignmentUndefine;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation NSMutableAttributedString (TUIRTL)
|
||||
- (void)setRtlAlignment:(TUITextRTLAlignment)rtlAlignment {
|
||||
switch (rtlAlignment) {
|
||||
case TUITextRTLAlignmentLeading:
|
||||
self.rtlAlignment = (isRTL() ? NSTextAlignmentRight : NSTextAlignmentLeft);
|
||||
break;
|
||||
case TUITextRTLAlignmentTrailing:
|
||||
self.rtlAlignment = (isRTL() ? NSTextAlignmentLeft : NSTextAlignmentRight);
|
||||
break;
|
||||
case TUITextRTLAlignmentCenter:
|
||||
self.rtlAlignment = NSTextAlignmentCenter;
|
||||
case TUITextRTLAlignmentUndefine:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
||||
BOOL isRTLString(NSString *string) {
|
||||
if ([string hasPrefix:@"\u202B"] || [string hasPrefix:@"\u202A"]) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSString * rtlString(NSString *string) {
|
||||
if (string.length == 0 || isRTLString(string)) {
|
||||
return string;
|
||||
}
|
||||
if (isRTL()) {
|
||||
string = [@"\u202B" stringByAppendingString:string];
|
||||
} else {
|
||||
string = [@"\u202A" stringByAppendingString:string];
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
NSAttributedString *rtlAttributeString(NSAttributedString *attributeString ,NSTextAlignment textAlignment ){
|
||||
if (attributeString.length == 0) {
|
||||
return attributeString;
|
||||
}
|
||||
NSRange range;
|
||||
NSDictionary *originAttributes = [attributeString attributesAtIndex:0 effectiveRange:&range];
|
||||
NSParagraphStyle *style = [originAttributes objectForKey:NSParagraphStyleAttributeName];
|
||||
|
||||
if (style && isRTLString(attributeString.string)) {
|
||||
return attributeString;
|
||||
}
|
||||
|
||||
NSMutableDictionary *attributes = originAttributes ? [originAttributes mutableCopy] : [NSMutableDictionary new];
|
||||
if (!style) {
|
||||
NSMutableParagraphStyle *mutableParagraphStyle = [[NSMutableParagraphStyle alloc] init];
|
||||
UILabel *test = [UILabel new];
|
||||
test.textAlignment = textAlignment;
|
||||
mutableParagraphStyle.alignment = test.textAlignment;
|
||||
style = mutableParagraphStyle;
|
||||
[attributes setValue:mutableParagraphStyle forKey:NSParagraphStyleAttributeName];
|
||||
}
|
||||
NSString *string = rtlString(attributeString.string);
|
||||
return [[NSAttributedString alloc] initWithString:string attributes:attributes];
|
||||
}
|
||||
|
||||
@implementation TUICollectionRTLFitFlowLayout
|
||||
- (UIUserInterfaceLayoutDirection)effectiveUserInterfaceLayoutDirection {
|
||||
if (isRTL()) {
|
||||
return UIUserInterfaceLayoutDirectionRightToLeft;
|
||||
}
|
||||
return UIUserInterfaceLayoutDirectionLeftToRight;
|
||||
}
|
||||
|
||||
- (BOOL)flipsHorizontallyInOppositeLayoutDirection{
|
||||
|
||||
return isRTL()? YES:NO;
|
||||
}
|
||||
@end
|
||||
Reference in New Issue
Block a user