iOS-中東鏡像翻轉(zhuǎn)+添加左滑返回手勢(shì)

一 序言
  • 中東國(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詳解

先看看效果圖


aribc.gif
四 開(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è)置pushpop時(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ì)
  1. 定義一個(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í)慣

  1. 新增左滑手勢(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)力撵术。

項(xiàng)目連接地址 - FDFullScreenPopGestureDemo

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末背率,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子嫩与,更是在濱河造成了極大的恐慌寝姿,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件划滋,死亡現(xiàn)場(chǎng)離奇詭異饵筑,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)处坪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門根资,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人同窘,你說(shuō)我怎么就攤上這事玄帕。” “怎么了想邦?”我有些...
    開(kāi)封第一講書人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵裤纹,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我丧没,道長(zhǎng)鹰椒,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任呕童,我火速辦了婚禮漆际,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘拉庵。我一直安慰自己灿椅,他們只是感情好套蒂,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布钞支。 她就那樣靜靜地躺著,像睡著了一般操刀。 火紅的嫁衣襯著肌膚如雪烁挟。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,541評(píng)論 1 305
  • 那天骨坑,我揣著相機(jī)與錄音撼嗓,去河邊找鬼柬采。 笑死,一個(gè)胖子當(dāng)著我的面吹牛且警,可吹牛的內(nèi)容都是我干的粉捻。 我是一名探鬼主播,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼斑芜,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼肩刃!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起杏头,我...
    開(kāi)封第一講書人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤盈包,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后醇王,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體呢燥,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年寓娩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了叛氨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡根暑,死狀恐怖力试,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情排嫌,我是刑警寧澤畸裳,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站淳地,受9級(jí)特大地震影響怖糊,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜颇象,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一伍伤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧遣钳,春花似錦扰魂、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至倦淀,卻和暖如春蒋畜,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背撞叽。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工姻成, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留插龄,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓科展,卻偏偏與公主長(zhǎng)得像均牢,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子才睹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1膨处、通過(guò)CocoaPods安裝項(xiàng)目名稱項(xiàng)目信息 AFNetworking網(wǎng)絡(luò)請(qǐng)求組件 FMDB本地?cái)?shù)據(jù)庫(kù)組件 SD...
    陽(yáng)明先生_X自主閱讀 15,980評(píng)論 3 119
  • 1、精細(xì)化管理砂竖;2真椿、激情教育;3乎澄、高效課堂 1突硝、精細(xì)化管理:領(lǐng)導(dǎo)值班,班主任值班置济,家長(zhǎng)參與解恰。骨干教師引領(lǐng),陪伴浙于,做...
    清澈與明亮閱讀 135評(píng)論 0 0
  • 剛畢業(yè)羞酗,在上海腐宋,暫時(shí)買不起房,所以和基友共三人合租一套三室一廳的房子檀轨。三只程序員胸竞,三個(gè)漢子,一起擼串参萄、一起王者榮耀...
    欒呱呱閱讀 771評(píng)論 6 9