一 序言
- 中東國(guó)家的人們使用習(xí)慣和其他國(guó)家不太一致奄侠,我們一般是從左往右看钝吮,但是中東的人們習(xí)慣從右往左看。
- 隨著大屏手機(jī)的出現(xiàn)碘勉,側(cè)滑返回功能就顯得至關(guān)重要巷挥。但是正常情況下,當(dāng)進(jìn)入一個(gè)新的頁(yè)面時(shí)验靡,新頁(yè)面是從右往左慢慢顯示倍宾。當(dāng)返回上一個(gè)頁(yè)面時(shí),右滑即可胜嗓。
- 但是中東國(guó)家恰恰相反高职,頁(yè)面時(shí)從左往右顯示,需要左滑返回上一個(gè)頁(yè)面辞州。
二 本文解決的問(wèn)題
- 如何正確處理系統(tǒng)語(yǔ)言和當(dāng)前APP語(yǔ)言問(wèn)題
- 如何做到中東鏡像
- 添加全面左滑手勢(shì)
三 準(zhǔn)備工作
- 本項(xiàng)目是通過(guò)第三方庫(kù)
FDFullscreenPopGesture
實(shí)現(xiàn)的怔锌,所以閱讀本文之前需要先熟悉該第三方庫(kù)的原理。傳輸?shù)刂? iOS-FDFullscreenPopGesture詳解
先看看效果圖
四 開(kāi)始講解啦
4.1 如何正確處理系統(tǒng)語(yǔ)言和當(dāng)前APP語(yǔ)言關(guān)系
本項(xiàng)目寫了一個(gè)類RTLHelper
,用于處理該問(wèn)題
#define AppLanguage @"AppLanguage"
#define ArabicLanguage @"ArabicLanguage"
#define EnglishLanguage @"EnglishLanguage"
// 判斷用戶當(dāng)前系統(tǒng)語(yǔ)言是否是阿語(yǔ)
+ (bool)isArabicSystemLanguage {
if (!isArabicKay) {
NSArray *languages = [NSLocale preferredLanguages];
NSString *currentLanguage = [languages objectAtIndex:0];
NSString *system_prefix_language = @"";
if ([currentLanguage containsString:@"-"]) {
NSArray *arr = [currentLanguage componentsSeparatedByString:@"-"];
system_prefix_language = arr[0];
} else {
system_prefix_language = currentLanguage;
}
isArabicKay = [NSNumber numberWithBool:[system_prefix_language isEqualToString:@"ar"]];
}
return [isArabicKay boolValue];
}
// 判斷當(dāng)前APP是否是阿語(yǔ)
+ (bool)isRTL {
NSString *language = [[NSUserDefaults standardUserDefaults] valueForKey:AppLanguage];
if ([language isEqualToString:ArabicLanguage]) {
return YES;
}
return NO;
}
4.2 如何做到中東鏡像翻轉(zhuǎn)
蘋果已經(jīng)幫我們做好了UI布局變動(dòng)的事項(xiàng)埃元,只要你的app是建立在約束環(huán)境中涝涤,并且實(shí)現(xiàn)了Leading以及Trailing兩個(gè)約束條件而不是Left和Right,那么岛杀,只要輸入幾句短短的代碼就可以輕松不費(fèi)力地完成整個(gè)UI布局的變動(dòng)阔拳。
/**
設(shè)置視圖方向
1.包括 push 和 pop 時(shí)的方向
2.包括視圖布局的方向
*/
+ (void)initRTL {
//APP阿拉伯語(yǔ)言
bool isRTL = [RTLHelper isRTL];
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"9.0") && isRTL) {
[[UIView appearance] setSemanticContentAttribute:UISemanticContentAttributeForceRightToLeft];
} else if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"9.0") && !isRTL) {
[[UIView appearance] setSemanticContentAttribute:UISemanticContentAttributeForceLeftToRight];
}
}
只要在AppDelegate
中調(diào)用該方法或者切換APP語(yǔ)言后調(diào)用方法即可。
1.該方法會(huì)設(shè)置視圖的布局方向类嗤,比如從右往左布局糊肠,還是從左往右布局
2.設(shè)置push
和pop
時(shí)的方向。
4.3 切換APP語(yǔ)言后需要做什么事情
1.保存當(dāng)前APP語(yǔ)言為新設(shè)置的語(yǔ)言(保存一個(gè)key)
2.設(shè)置當(dāng)前APP的布局方向土浸,即semanticContentAttribute
參數(shù)
3.移除棧中所有控制器罪针,并且給window
設(shè)置一個(gè)新的rootVC
,然后回到根控制器即可
相關(guān)代碼如下
- 保存當(dāng)前APP語(yǔ)言為新設(shè)置的語(yǔ)言(保存一個(gè)key)
[[NSUserDefaults standardUserDefaults] setValue:self.appLanguage forKey:AppLanguage];
[[NSUserDefaults standardUserDefaults] synchronize];
- 設(shè)置當(dāng)前APP的布局方向黄伊,即
semanticContentAttribute
參數(shù)
/**
設(shè)置視圖方向
1.包括 push 和 pop 時(shí)的方向
2.包括視圖布局的方向
*/
+ (void)initRTL {
//APP阿拉伯語(yǔ)言
bool isRTL = [RTLHelper isRTL];
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"9.0") && isRTL) {
[[UIView appearance] setSemanticContentAttribute:UISemanticContentAttributeForceRightToLeft];
} else if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"9.0") && !isRTL) {
[[UIView appearance] setSemanticContentAttribute:UISemanticContentAttributeForceLeftToRight];
}
}
- 移除棧中所有控制器泪酱,并且給
window
設(shè)置一個(gè)新的rootVC
,然后回到根控制器即可
// 新增TabBar后直接處理為重設(shè)APP界面
+ (void)setController {
NSMutableArray *tbViewControllers = [NSMutableArray arrayWithArray:[[IContext getCtx].rootTabBarController viewControllers]];
// 移除棧中所有控制器
for (BaseNavigationController *navVc in tbViewControllers) {
for (BaseViewController *vc in navVc.childViewControllers) {
[vc removeFromParentViewController];
}
}
[tbViewControllers removeAllObjects];
[[IContext getCtx].rootTabBarController setViewControllers:tbViewControllers];
// 給window設(shè)置一個(gè)新的根控制器
MainViewController *tb = [[MainViewController alloc] init];
[IContext getCtx].rootTabBarController = tb;
[[IContext getCtx].rootWindow setRootViewController:tb];
[[IContext getCtx].rootWindow makeKeyWindow];
}
[self.navigationController popToRootViewControllerAnimated:YES];
4.4 添加左滑手勢(shì)
- 定義一個(gè)左滑的手勢(shì)的類
- RTLEdgePanGesture
@interface RTLEdgePanGesture : UIScreenEdgePanGestureRecognizer
@end
@implementation RTLEdgePanGesture
// 當(dāng)手勢(shì)側(cè)滑時(shí)會(huì)調(diào)用該方法,取到的是手指移動(dòng)后还最,在相對(duì)坐標(biāo)中的偏移量
// 注意:如果系統(tǒng)是阿語(yǔ),手勢(shì)已經(jīng)做了特殊處理,所以這個(gè)時(shí)候使用系統(tǒng)默認(rèn)的就好
- (CGPoint)translationInView:(UIView *)view {
if ([RTLHelper isArabicSystemLanguage] && [RTLHelper isRTL]) {
// APP 為阿語(yǔ)
return [super translationInView:view];
}
if ([UIDevice currentDevice].systemVersion.doubleValue > 9.0) {
CGPoint oldP = [super translationInView:view];
// app為阿語(yǔ) 系統(tǒng)不是 反向處理
return CGPointMake(-oldP.x, oldP.y);
}
return [super translationInView:view];
}
@end
1.
如果系統(tǒng)是阿語(yǔ)言墓阀,并且APP也是阿語(yǔ),則直接調(diào)用系統(tǒng)的方法即可拓轻,因?yàn)橄到y(tǒng)以及替我們做好了斯撮。這是一個(gè)大坑
。
2.當(dāng)手勢(shì)在屏幕拖拽時(shí)扶叉,會(huì)調(diào)用該方法勿锅,從而返回當(dāng)前點(diǎn)擊區(qū)域的坐標(biāo)
添加一個(gè)左滑手勢(shì)的實(shí)例
fd_rtlFullscreenPopGestureRecognizer
- (UIScreenEdgePanGestureRecognizer *)fd_rtlFullscreenPopGestureRecognizer {
UIScreenEdgePanGestureRecognizer *rtlPanGestureRecognizer = objc_getAssociatedObject(self, _cmd);
if (!rtlPanGestureRecognizer) {
rtlPanGestureRecognizer = [[RTLEdgePanGesture alloc] init];
rtlPanGestureRecognizer.edges = UIRectEdgeRight;
if ([RTLHelper isArabicSystemLanguage] && ![RTLHelper isRTL]) {
// APP 不是阿語(yǔ),強(qiáng)制把 APP 換成原來(lái)的
rtlPanGestureRecognizer.edges = UIRectEdgeLeft;
}
objc_setAssociatedObject(self, _cmd, rtlPanGestureRecognizer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return rtlPanGestureRecognizer;
}
注意:如果系統(tǒng)是阿語(yǔ),但是APP語(yǔ)言不是阿語(yǔ)枣氧,則需要把操作習(xí)慣變成正常的使用習(xí)慣
- 新增左滑手勢(shì)的代理
_FDFullRTLScreenPopGestureRecognizerDelegate
@interface _FDFullRTLScreenPopGestureRecognizerDelegate : NSObject <UIGestureRecognizerDelegate>
@property (nonatomic, weak) UINavigationController *navigationController;
@end
@implementation _FDFullRTLScreenPopGestureRecognizerDelegate
// 判斷當(dāng)前界面是否支持手勢(shì)滑動(dòng)返回
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
// Ignore when no view controller is pushed into the navigation stack.
if (self.navigationController.viewControllers.count <= 1) {
return NO;
}
// Ignore when the active view controller doesn't allow interactive pop.
UIViewController *topViewController = self.navigationController.viewControllers.lastObject;
if (topViewController.fd_interactivePopDisabled) {
return NO;
}
// Ignore when the beginning location is beyond max allowed initial distance to left edge.
CGPoint beginningLocation = [gestureRecognizer locationInView:gestureRecognizer.view];
CGFloat maxAllowedInitialDistance = topViewController.fd_interactivePopMaxAllowedInitialDistanceToLeftEdge;
if (maxAllowedInitialDistance > 0 && beginningLocation.x > maxAllowedInitialDistance) {
return NO;
}
// Ignore pan gesture when the navigation controller is currently in transition.
if ([[self.navigationController valueForKey:@"_isTransitioning"] boolValue]) {
return NO;
}
return YES;
}
- 定義左滑代理的實(shí)例
- (_FDFullRTLScreenPopGestureRecognizerDelegate *)fd_popRTLGestureRecognizerDelegate {
_FDFullRTLScreenPopGestureRecognizerDelegate *rtlDelegate = objc_getAssociatedObject(self, _cmd);
if (!rtlDelegate) {
rtlDelegate = [[_FDFullRTLScreenPopGestureRecognizerDelegate alloc] init];
rtlDelegate.navigationController = self;
objc_setAssociatedObject(self, _cmd, rtlDelegate, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return rtlDelegate;
}
3. 在fd_pushViewController:
方法中替換系統(tǒng)自帶的手勢(shì)
- (void)fd_pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
// 自定義的手勢(shì)直接添加到interactivePopGestureRecognizer對(duì)應(yīng)的View上。
// 實(shí)際上就是將系統(tǒng)的手勢(shì)事件轉(zhuǎn)發(fā)為自定義的手勢(shì)达吞,觸發(fā)的事件不變
// doc:http://t.cn/RssK6mz 處理阿語(yǔ)翻轉(zhuǎn)手勢(shì)
// 當(dāng)前APP語(yǔ)言為阿語(yǔ) || 系統(tǒng)語(yǔ)言為阿語(yǔ)
if ([RTLHelper isArabicSystemLanguage] || [RTLHelper isRTL]) {
if (![self.interactivePopGestureRecognizer.view.gestureRecognizers containsObject:self.fd_rtlFullscreenPopGestureRecognizer]) {
// Add our own gesture recognizer to where the onboard screen edge pan gesture recognizer is attached to.
[self.interactivePopGestureRecognizer.view addGestureRecognizer:self.fd_rtlFullscreenPopGestureRecognizer];
// Forward the gesture events to the private handler of the onboard gesture recognizer.
// interactivePopGestureRecognizer會(huì)操作一個(gè)指定的target , action “handleNavigationTransition”,
// 通過(guò)Runtime動(dòng)態(tài)獲取到指定的target, 及action添加到自定義的手勢(shì)上酪劫。
NSArray *internalTargets = [self.interactivePopGestureRecognizer valueForKey:@"targets"];
// get releate target
id internalTarget = [internalTargets.firstObject valueForKey:@"target"];
// get handleNavigationTransition sel
SEL internalAction = NSSelectorFromString(@"handleNavigationTransition:");
self.fd_rtlFullscreenPopGestureRecognizer.delegate = self.fd_popRTLGestureRecognizerDelegate;
// add target and action to this gesture
[self.fd_rtlFullscreenPopGestureRecognizer addTarget:internalTarget action:internalAction];
// Disable the onboard gesture recognizer.
self.interactivePopGestureRecognizer.enabled = NO;
}
} else {
// 添加一個(gè)正常的手勢(shì)即可
}
}
只要系統(tǒng)語(yǔ)言為阿語(yǔ)或者APP語(yǔ)言是阿語(yǔ)刻剥,就添加阿語(yǔ)手勢(shì)
- 到此為止,工作完成滩字,我們就給中東鏡像添加了一個(gè)左滑手勢(shì)透敌,是不是很爽啊盯滚。
- 如有錯(cuò)誤,歡迎指正酗电,多多點(diǎn)贊魄藕,打賞更佳,您的支持是我寫作的動(dòng)力撵术。