IOS導(dǎo)航欄透明漸變效果二(導(dǎo)航欄側(cè)滑漸變效果)

上一篇已經(jīng)完成了導(dǎo)航欄效果的漸變垄惧。但是側(cè)滑返回的時(shí)候遏片,導(dǎo)航欄從不透明界面跳轉(zhuǎn)到透明界面時(shí)薯嗤,總是會(huì)突變顽爹,感覺(jué)很膈應(yīng)。這里將用runtime截獲系統(tǒng)的方法來(lái)完成對(duì)導(dǎo)航欄動(dòng)畫的逆襲

由于監(jiān)測(cè)側(cè)滑手勢(shì)的方法是系統(tǒng)管理的骆姐,并沒(méi)有暴露給我們镜粤。所以我們先要做一些準(zhǔn)備工作:

利用Runtime 獲取方法、屬性玻褪、成員屬性繁仁。

- (NSArray *)getAllMethods {
    unsigned int count = 0;
    Method *list = class_copyMethodList([self class], &count);
    
    NSMutableArray *methodArray = [NSMutableArray array];
    for (int i = 0; i < count; i++) {
        Method method = list[i];
        
        SEL name = method_getName(method);
        unsigned int params = method_getNumberOfArguments(method);
        const char *encode = method_getTypeEncoding(method);
        const char *name_c = sel_getName(name);
        
        NSString *str = [NSString stringWithFormat:@"方法名:%s, 參數(shù)個(gè)數(shù):%d, 參數(shù)類型: %s", name_c, params, encode];
        [methodArray addObject:str];
    }
    free(list);
    return methodArray;
}

- (NSArray *)getAllProperties
{
    unsigned int count = 0;
    objc_property_t *properties  =class_copyPropertyList([self class], &count);
    
    NSMutableArray *propertiesArray = [NSMutableArray arrayWithCapacity:count];
    
    for (int i = 0; i < count ; i++)
    {
        objc_property_t property = properties[i];
        const char* propertyName =property_getName(property);
        [propertiesArray addObject: [NSString stringWithUTF8String:propertyName]];
    }
    free(properties);
    return propertiesArray;
}

- (NSArray *)getAllIvars {
    
    unsigned int count = 0;

    NSMutableArray *ivarArray = [NSMutableArray array];
    
    Ivar *ivars = class_copyIvarList([self class], &count);
    
    for (int i = 0; i< count; i++) {
        Ivar ivar = ivars[i];
        
        const char *name = ivar_getName(ivar);
        const char *encode = ivar_getTypeEncoding(ivar);
        NSString *str = [NSString stringWithFormat:@"%s, %s", name, encode];
        
        [ivarArray addObject:str];
    }
    free(ivars);
    return ivarArray;
}

保存UIViewController導(dǎo)航欄的alpha值:

這里有兩種方法:

方法一:所有控制都繼承一個(gè)RootController。在RootController里面添加alpha屬性归园。
方法二:添加UIViewController的Category,在Category里面添加alpha屬性稚矿,但是需要runtime重寫set 和 get方法庸诱。

static NSString *alphaKey = @"alphaKey";

@implementation UIViewController (alpha)

@dynamic navAlpha;

- (CGFloat)navAlpha {
    CGFloat alpha = [objc_getAssociatedObject(self, &alphaKey) floatValue];
    return alpha;
}

- (void)setNavAlpha:(CGFloat)navAlpha {
    objc_setAssociatedObject(self, &alphaKey, @(navAlpha), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    [self setNavigationBarAlpha:navAlpha];
}

獲取UINavigationController方法列表:

NSArray *methodArr = [UINavigationController getAllMethods];
NSLog(@"%@",methodArr);

由于之前自己找UINavigationController中的方法的時(shí)候點(diǎn)到UIViewControllerAnimatedTransitioning這個(gè)里面翻閱了一下發(fā)現(xiàn)有兩個(gè)協(xié)議里面都有下面幾個(gè)關(guān)于 過(guò)度交互 的方法,于是互在打印的方法數(shù)組里也查下發(fā)現(xiàn)也有于是就嘗試了一下晤揣,發(fā)現(xiàn)果然是這幾個(gè)方法:

- (void)updateInteractiveTransition:(CGFloat)percentComplete;
- (void)cancelInteractiveTransition;
- (void)finishInteractiveTransition;
UINavigationController 過(guò)度交互.png

這里參數(shù)類型 “v24@0:8d16” 這里v表示返回值類型為void桥爽,后面的d16表示參數(shù)類型為double類型,與上面方法一致昧识。

然后我們對(duì)上面幾個(gè)方法進(jìn)行方法交換钠四,系統(tǒng)相應(yīng)該方法的時(shí)候能完成自己想做的事:

NSArray *arr = @[@"_updateInteractiveTransition:", @"_cancelInteractiveTransition:transitionContext:", @"_finishInteractiveTransition:transitionContext:"];
    for (int i = 0; i < arr.count; i++) {
        NSString *mySel = [NSString stringWithFormat:@"yhh%@", arr[i]];
        Method sysMethod = class_getInstanceMethod(self, NSSelectorFromString(arr[i]));
        Method myMethod = class_getInstanceMethod(self, NSSelectorFromString(mySel));
        method_exchangeImplementations(sysMethod, myMethod);
    }
/*
 *此方法在手指在屏幕上,側(cè)滑返回過(guò)程中調(diào)用跪楞。
**/
- (void)yhh_updateInteractiveTransition:(CGFloat)percentComplete {
    // percentComplete是當(dāng)前移動(dòng)距離與屏幕的比例
    NSLog(@"%f", percentComplete);
    UIViewController *topvc = self.topViewController;
    
    id <UIViewControllerTransitionCoordinator> tran = topvc.transitionCoordinator;
    // fromvc 從哪個(gè)控制來(lái)缀去, tovc去哪個(gè)控制器
    UIViewController *fromvc = [tran viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController *tovc = [tran viewControllerForKey:UITransitionContextToViewControllerKey];
    NSLog(@"fromvc:%f  -----tovc:%f", fromvc.navAlpha, tovc.navAlpha);
    
    CGFloat alpha = fromvc.navAlpha - (fromvc.navAlpha - tovc.navAlpha) * percentComplete;
    [self setNavigationBarAlpha:alpha];
    [self yhh_updateInteractiveTransition:percentComplete];
}
/*
 *側(cè)滑返回手勢(shì)松手時(shí)不能pop回上一界面時(shí)調(diào)用(滑動(dòng)小于一半屏幕)。
 *此處context由于不知道是什么類型甸祭,里面有什么屬性缕碎,成員變量所以用了runtime查看context及context的superclass.
 *在context.superclass里面發(fā)現(xiàn)了_duration 成員變量利用kvc拿到_duration的值使用
**/
- (void)yhh_cancelInteractiveTransition:(CGFloat)percentComplete transitionContext:(id)context {
    UIViewController *fromvc = [context viewControllerForKey:UITransitionContextFromViewControllerKey];
    
//    NSLog(@"%@", [[context superclass] getAllProperties]);
//    NSLog(@"%f-%f--%@", percentComplete, [[context valueForKey:@"_duration"] floatValue] , NSStringFromClass([context class]));
    
    [UIView animateWithDuration:[[context valueForKey:@"_duration"] floatValue] * percentComplete animations:^{
        [self setNavigationBarAlpha:fromvc.navAlpha];
    }];
    [self yhh_cancelInteractiveTransition:percentComplete transitionContext:context];
}


取消手勢(shì)時(shí)context內(nèi)部屬性.png
取消手勢(shì)時(shí)context_superclass內(nèi)部屬性.png
 /*
 *側(cè)滑返回手勢(shì)松手時(shí)能夠pop回上一界面時(shí)調(diào)用(滑動(dòng)大于一半屏幕)
**/
- (void)yhh_finishInteractiveTransition:(CGFloat)percentComplete transitionContext:(id)context {
    UIViewController *tovc = [context viewControllerForKey:UITransitionContextToViewControllerKey];
    
    [UIView animateWithDuration:[[context valueForKey:@"_duration"] floatValue]*(1 - percentComplete) animations:^{
        [self setNavigationBarAlpha:tovc.navAlpha];
    }];
    [self yhh_finishInteractiveTransition:percentComplete transitionContext:context];
}

設(shè)置導(dǎo)航欄alpha值

/*
 *這里由于直接修改UINavigationBar.subviews[0]的alpha值會(huì)導(dǎo)致漸變過(guò)程中沒(méi)有毛玻璃效果。
 *#所以利用runtime查看成員變量拿到然后kvc拿到_backgroundEffectView修改其alpha
**/

- (void)setNavigationBarAlpha:(CGFloat)alpha {
    UIView *backView = self.navigationBar.subviews[0];
    NSLog(@"%s, %f", __func__, alpha);
    UIView *shadow = [backView valueForKey:@"_shadowView"];
    if (shadow) {
        shadow.alpha = alpha;
    }
    
    UIView *effectView = [backView valueForKey:@"_backgroundEffectView"];
    if (effectView) {
        effectView.alpha = alpha;
    }
}

最終效果:

側(cè)滑導(dǎo)航欄漸變.gif

附上gitub鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末池户,一起剝皮案震驚了整個(gè)濱河市咏雌,隨后出現(xiàn)的幾起案子凡怎,更是在濱河造成了極大的恐慌,老刑警劉巖赊抖,帶你破解...
    沈念sama閱讀 218,640評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件统倒,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡氛雪,警方通過(guò)查閱死者的電腦和手機(jī)房匆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)注暗,“玉大人坛缕,你說(shuō)我怎么就攤上這事±瑁” “怎么了赚楚?”我有些...
    開(kāi)封第一講書人閱讀 165,011評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)骗卜。 經(jīng)常有香客問(wèn)我宠页,道長(zhǎng),這世上最難降的妖魔是什么寇仓? 我笑而不...
    開(kāi)封第一講書人閱讀 58,755評(píng)論 1 294
  • 正文 為了忘掉前任举户,我火速辦了婚禮,結(jié)果婚禮上遍烦,老公的妹妹穿的比我還像新娘俭嘁。我一直安慰自己,他們只是感情好服猪,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,774評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布供填。 她就那樣靜靜地躺著,像睡著了一般罢猪。 火紅的嫁衣襯著肌膚如雪近她。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,610評(píng)論 1 305
  • 那天膳帕,我揣著相機(jī)與錄音粘捎,去河邊找鬼。 笑死危彩,一個(gè)胖子當(dāng)著我的面吹牛攒磨,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播汤徽,決...
    沈念sama閱讀 40,352評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼咧纠,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了泻骤?” 一聲冷哼從身側(cè)響起漆羔,我...
    開(kāi)封第一講書人閱讀 39,257評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤梧奢,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后演痒,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體亲轨,經(jīng)...
    沈念sama閱讀 45,717評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,894評(píng)論 3 336
  • 正文 我和宋清朗相戀三年鸟顺,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了惦蚊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,021評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡讯嫂,死狀恐怖蹦锋,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情欧芽,我是刑警寧澤莉掂,帶...
    沈念sama閱讀 35,735評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站千扔,受9級(jí)特大地震影響憎妙,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜曲楚,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,354評(píng)論 3 330
  • 文/蒙蒙 一厘唾、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧龙誊,春花似錦抚垃、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,936評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至护昧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間粗截,已是汗流浹背惋耙。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,054評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留熊昌,地道東北人绽榛。 一個(gè)月前我還...
    沈念sama閱讀 48,224評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像婿屹,于是被迫代替她去往敵國(guó)和親灭美。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,974評(píng)論 2 355

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