多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內(nèi)最全IT社區(qū)平臺 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當前位置:首頁 > php開源 > 綜合技術(shù) > 實現(xiàn)像網(wǎng)易新聞那樣全屏push/pop

實現(xiàn)像網(wǎng)易新聞那樣全屏push/pop

來源:程序員人生   發(fā)布時間:2016-07-13 08:32:29 閱讀次數(shù):3197次

來自Leo的原創(chuàng)博客,轉(zhuǎn)載請著名出處

我的StackOverflow

profile for Leo on Stack Exchange, a network of free, community-driven Q&A sites

我的Github
https://github.com/LeoMobileDeveloper


目標效果

  • 全屏幕左滑-進行導航交互式推出
  • 全屏幕右滑-進行導航交互式推入
  • 修改默許的導航欄push/Pop


怨言幾句

本來想著用兩種方式:繼承UINavigationController和用Runtime動態(tài)修改UINavigationController的實現(xiàn)來完成這篇博客的。最近,看美劇有點分心,又忙著整理React Native的東西,用Runtime來實現(xiàn)的部份就還沒寫完。所以,這篇博客就拆分成兩篇吧,今天先把繼承UINavigationController的方式寫出來,后面的在說。


LHNavigationController

寫了個簡單的庫LHNavigationController
看看效果,提供了兩種效果,分別模仿網(wǎng)易新聞和斗魚

網(wǎng)易新聞

斗魚

原理

  • LHNavigationController設(shè)置delegateself,來重寫交互式轉(zhuǎn)場動畫

  • 通過為LHNavigationController添加兩個pan手勢,來分別控制push/pop

  • LHViewControllerUIViewController的子類,自帶1個NavigationBar

  • LHTableViewController 繼承自LHViewController添加了1個Tableview,來給子類調(diào)用

當前的代碼缺點:

  1. 所有Controller需要繼承自LHViewController 或 LHTableViewController,對代碼影響較大(這個缺點不可避免的)

  2. NavigationBar沒法透明(這個后續(xù)會解決)


UINavigationControllerDelegate

UINavigationController有1個屬性是delegate

@property(nonatomic, weak) id< UINavigationControllerDelegate > delegate

這是1個遵守UINavigationControllerDelegate的對象,通過設(shè)置delegate,我們可以重新定義push/pop的轉(zhuǎn)場動畫。這個協(xié)議中,我們主要用到以下兩個方法

- navigationController:animationControllerForOperation:fromViewController:toViewController: - navigationController:interactionControllerForAnimationController:

其中,

第1個方法返回1個id<UIViewControllerAnimatedTransitioning>對象。用來提供轉(zhuǎn)場動畫

第2個方法返回id<UIViewControllerInteractiveTransitioning>對象。用來提供交互式轉(zhuǎn)場的控制器

更直觀的表述就是:第1個控制在轉(zhuǎn)場的時候,兩個viewController各自若何動畫,第2個用來控制動畫的進度


1個通用的Animator

通過上文的描寫我們知道,SDK給我們的接口是實現(xiàn)某個協(xié)議便可。那末,實現(xiàn)id<UIViewControllerAnimatedTransitioning>的對象我們就能夠單獨創(chuàng)建1個類,方便復用。

由通過1個類來處理push/pop,所以我們需要辨別,定義1個枚舉

typedef NS_ENUM(NSInteger,LHNavAnimatorOperation){ LHNavAnimatorOperationPush, LHNavAnimatorOperationPop, };

然后,接口定義看起來是這模樣的

@interface LHNavAnimator : NSObject<UIViewControllerAnimatedTransitioning> //初始化,設(shè)置push/pop,綁定的navigationController -(instancetype)initWithDirection:(LHNavAnimatorOperation)direction navigation:(UINavigationController *)nav; //方向 @property (assign,nonatomic)LHNavAnimatorOperation operation; //綁定的navigationController,為了在轉(zhuǎn)場結(jié)束/取消的時候禁用手勢 @property (weak,nonatomic)UINavigationController * nav; @end

UIViewControllerAnimatedTransitioning協(xié)議規(guī)定要實現(xiàn)以下兩個方法

//動畫的時間,這里的transitionContext是轉(zhuǎn)場上下文,由系統(tǒng)提供,通過這個來獲得前后兩個ViewController - (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext{ return 0.3; } //實際的動畫 - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext{ // }

Tips:交互式轉(zhuǎn)場的動畫最好用UIView層次的API來實現(xiàn)

然后,我們來看看動畫的具體實現(xiàn),這里動畫的本質(zhì)是

  • UINavigationController提供1個ContainView作為動畫的容器
  • 獲得到兩個View,1個是當前現(xiàn)實的View,1個是行將顯示的View
  • 轉(zhuǎn)場的本質(zhì)就是當前顯示View移除,行將顯示View進入
//獲得ViewController/fromview/toview/containview UIViewController * fromvc = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; UIViewController * tovc = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; UIView * fromView = fromvc.view; UIView * toView = tovc.view; UIView * containView = [transitionContext containerView]; CGFloat duration = [self transitionDuration:transitionContext]; CGFloat toTransition = CGRectGetWidth(containView.bounds); //系統(tǒng)默許的轉(zhuǎn)場距離是全部containView的0.3 CGFloat fromTranstion = toTransition * 0.3; //Add subview [containView addSubview:toView]; if (_operation == LHNavAnimatorOperationPush) { //禁用手勢 _nav.view.userInteractionEnabled = NO; toView.transform = CGAffineTransformMakeTranslation(toTransition, 0); fromView.transform = CGAffineTransformIdentity; [containView bringSubviewToFront:toView]; //動畫很簡單,就是不同View相同時間移動距離不1樣,這樣移動的速度就不1樣 [UIView animateWithDuration:duration delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{ toView.transform = CGAffineTransformIdentity; fromView.transform = CGAffineTransformMakeTranslation(-1 * fromTranstion, 0); } completion:^(BOOL finished) { //結(jié)束的時候,恢復狀態(tài) _nav.view.userInteractionEnabled = YES; fromView.transform = CGAffineTransformIdentity; toView.transform = CGAffineTransformIdentity; //通知轉(zhuǎn)場上下文,轉(zhuǎn)場結(jié)束 BOOL canceled = [transitionContext transitionWasCancelled]; [transitionContext completeTransition:!canceled]; }]; }else{ //... }

交互式轉(zhuǎn)場控制器

上文提到了,為了自定義交互式轉(zhuǎn)場,我們還需要返回這樣1個對象

id<UIViewControllerInteractiveTransitioning>

慶幸的是,系統(tǒng)為我們提供了1個類UIPercentDrivenInteractiveTransition,通常我們只需要用這個類或繼承便可。主要用到以下3個方法

//更新轉(zhuǎn)場進度,比如0.5表示轉(zhuǎn)場進行了1半 updateInteractiveTransition: //轉(zhuǎn)場取消了 cancelInteractiveTransition //轉(zhuǎn)場結(jié)束了 finishInteractiveTransition

由于,有些轉(zhuǎn)場是按鍵驅(qū)動,其實不是手勢拖動,所以要支持非交互式轉(zhuǎn)場。我們保存1個屬性

@property (assign,nonatomic)BOOL isInteractive;

然后,交互式轉(zhuǎn)場的時候,就反悔self.transition(UIPercentDrivenInteractiveTransition)對象

- (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController{ return _isInteractive ? self.transition : nil; }

交互式push/Pop

UINavigationControllerDelegate協(xié)議需要的兩個對象我們準備好了,接下來需要手勢來驅(qū)動轉(zhuǎn)場了。這里push較為麻煩,主要講授push。

在LHNavigationController的ViewDidLoad中,添加push手勢

self.pushPan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePush:)]; self.pushPan.delegate = self; self.pushPan.cancelsTouchesInView = NO; [self.view addGestureRecognizer:self.pushPan];

在看看如何處理的手勢

- (void)handlePush:(UIScreenEdgePanGestureRecognizer *)sender{ //計算距離 CGFloat tx = [sender translationInView:self.view].x; //計算進度 CGFloat pec = fabs(tx/CGRectGetWidth(self.view.frame)); //獲得速度 CGFloat vx = [sender velocityInView:self.view].x; if (sender.state == UIGestureRecognizerStateBegan) {//手勢開始的時候,掉用代理來獲得下1個Controller,push到當前堆棧 self.isInteractive = YES; UIViewController * nextvc = [self.lhDelegate viewControllerAfterController:self.viewControllers.lastObject]; [self pushViewController:nextvc animated:YES]; }else if (sender.state == UIGestureRecognizerStateChanged) { //根據(jù)手勢移動,更新轉(zhuǎn)場進度 [self.transition updateInteractiveTransition:pec]; }else if (sender.state == UIGestureRecognizerStateEnded || sender.state == UIGestureRecognizerStateCancelled) { //手勢結(jié)束的時候,根據(jù)速度判斷push是不是成功 if (vx > 0) {// [self.transition cancelInteractiveTransition]; }else{ [self.transition finishInteractiveTransition]; } self.isInteractive = NO; } }

這里的lhDelegate是1個代理對象

@protocol LHNavigationControllerDelegate<NSObject> //返回controller的下1個Controller - (UIViewController *)viewControllerAfterController:(UIViewController *)controller; @end

LHViewController

然后,我們來看看LHViewController如何實現(xiàn)自己自帶NavigationBar

聲明3個屬性

@property (strong,nonatomic,readonly)UINavigationBar * lh_navigationBar; @property (strong,nonatomic,readonly)UINavigationItem * lh_navigationItem; @property (strong,nonatomic,readonly)UIView * lh_view;

3個屬性都惰性初始化

- (UIView *)lh_view{ if (_lh_view == nil) { _lh_view = [[UIView alloc] init]; } return _lh_view; } //...


Tips:惰性初始化是為了避免在ViewDidLoad還沒有掉用的時候,進行屬性設(shè)置無效

然后,在ViewDidLoad中,添加NavigationBar,添加lh_view作為容器,設(shè)置AutoLayout

- (void)viewDidLoad{ [super viewDidLoad]; self.lh_navigationBar.translatesAutoresizingMaskIntoConstraints = NO; self.lh_navigationBar.items = @[self.lh_navigationItem]; [self.view addSubview:_lh_navigationBar]; self.lh_view.translatesAutoresizingMaskIntoConstraints = NO; [self.view addSubview:_lh_view]; //束縛很簡單,可視化語言以下 //水平 H:|-0-[_lh_view]-0-|,H:|-0-[_lh_navigationBar]-0-| //垂直 V:[topLayoutGuide]-0-[_lh_navigationBar]-0-[_lh_view]-0| [self.view bringSubviewToFront:self.lh_navigationBar]; self.view.backgroundColor = [UIColor whiteColor]; self.lh_navigationBar.translucent = NO; }

StatusBar背風景

這里的設(shè)置是通過self.view作為StatusBar背風景的填充,所以設(shè)置的時候,應當是這么設(shè)置的

- (void)setBarTintColor:(UIColor *)barTintColor{ _barTintColor = barTintColor; self.view.backgroundColor = barTintColor; self.lh_navigationBar.barTintColor = barTintColor; }

實現(xiàn)方式2

其實實現(xiàn)像網(wǎng)易新聞那樣pop,還有1個實現(xiàn)方式。

這類方式的原理以下

  • 每一個ViewController自帶1個NavigationController
  • NavigationController作為childController添加到containViewController中

這樣,每次push的時候,都push1個containViewController,而根NavigationController的導航欄是隱藏的。

這時候候,每個ViewController的層次架構(gòu)以下

… RootNavigationController
……ContainViewController
………NavigationController
…………業(yè)務Controller

前段時間自己獨立開發(fā)的這個項目就是用的這類視圖架構(gòu)。

你需要1個Manager來處理對應的邏輯,減少代碼量。配合頁面路由的技術(shù)架構(gòu),使用起來更好。


總結(jié)

這兩種App的架構(gòu),合適從App 的初始階段使用。由于,

第1種

  • 你所有的類都需要繼承自LHViewController.
  • 你添加SubView,刪除subview的時候,需要通過self.lh_view來實現(xiàn)。

第2種模式

  • 你所有的Controller都需要自帶1個NavigationController,并且放到1個容器里

對全部的視圖控制器的架構(gòu)影響都很大。這里寫出來,作為1種思路吧。

生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 中文字幕资源在线 | 免费一级欧美片片线观看 | 特级毛片女人18毛片 | 国产模特众筹精品视频 | 国内精品久久久久影院不卡 | 欧美日韩国产另类一区二区三区 | 亚洲资源最新版在线观看 | 亚洲精品自产拍在线观看 | 欧美性高清另类videosex | 久久一区二区三区不卡 | 欧式午夜理伦三级在线观看 | 日韩爱爱网 | 国产精品人成人免费国产 | 国产成人精品视频一区 | 日韩精品一区二区三区视频网 | 欧美妇性猛交视频 | 精品一区二区久久久久久久网站 | 看一级黄色毛片 | 最新99国产成人精品视频免费 | 影院成人区精品一区二区婷婷丽春院影视 | 欧美激情在线播放一区二区三区 | 国产一区二区视频在线播放 | 国产精品v欧美精品v日韩精品 | 99精品福利 | 日本一级免费 | 手机看片福利久久 | 国产亚洲精品成人一区看片 | ak福利午夜在线观看 | 成年人性生活免费视频 | 国产成人高清亚洲一区久久 | 欧洲精品一区二区三区 | 国产精品高清一区二区 | 欧美日韩免费 | 中文字幕第八页 | 国产69成人免费视频观看 | 国产精品亚洲精品久久成人 | 日本一区二区在线视频 | www在线观看免费 | 欧美综合视频在线 | 日本无卡码免费一区二区三区 | 免费福利在线观看 |