一個(gè)絲滑的全屏滑動返回手勢

原文地址:一個(gè)絲滑的全屏滑動返回手勢

全屏返回手勢

自 iOS7 之后蚓聘,Apple 增加了屏幕邊緣右劃返回交互的支持吟策,再配合上 UINavigationController 的交互式動畫撤卢,pop 到上一級頁面的操作變的非常順暢和絲滑僻澎,從此废累,我很少再使用點(diǎn)擊左上角導(dǎo)航欄上的返回按鈕的方式返回了虑绵,因?yàn)檫@對單手操作十分不友好防泵;如果一個(gè) App 居然膽敢不支持滑動返回蚀之,那離被卸載就不遠(yuǎn)了。

說到全屏返回手勢捷泞,首先我感覺這件事本身可能就有問題足删,畢竟有點(diǎn)反蘋果官方的交互,讓用戶從任意的地方都能夠滑動返回這個(gè)交互在國內(nèi)的 App 中非常普遍锁右,比如我手機(jī)中的手Q失受、微博、網(wǎng)易新聞咏瑟、大眾點(diǎn)評等拂到,當(dāng)然還有百度知道- -。這里得對微信的產(chǎn)品經(jīng)理們得點(diǎn)個(gè)贊码泞,從整個(gè) App 來看兄旬,不論是交互還是 UI 結(jié)構(gòu)和樣式都非常的 iOS,沒有什么特別奇葩的頁面和交互余寥,以至于使用 UIKit 原生的框架可以非常簡單的搭建起來领铐,這也符合我個(gè)人對 App 的一個(gè)愿景:一個(gè)優(yōu)秀的 App 不論從用戶角度看還是從代碼角度看都應(yīng)該是簡單且優(yōu)雅的,呼吁各家產(chǎn)品經(jīng)理可以多借鑒下像微信這樣很本色的 App 設(shè)計(jì)宋舷。(以后可以分享下如何使用 Storyboard 在一小時(shí)內(nèi)快速搭建起微信 UI)

FDFullscreenPopGesture

工作畢竟是工作绪撵,于是乎所以就被迫實(shí)現(xiàn)了套 pan 手勢處理加截圖和視差,雖然在運(yùn)動曲線上祝蝠、bar 截圖處理上下了不少功夫音诈,但距離系統(tǒng)的絲滑效果還是差距挺遠(yuǎn)。隨時(shí)間推移绎狭,終于能夠最低支持 iOS7 后细溅,我們把這個(gè)問題再次拿出來討論和研究,直到在微博上看到了J_雨同學(xué)的這篇文章后才找到了這個(gè)迄今為止最簡單的解決方案坟岔。于是乎在他的授權(quán)下谒兄,我們在 forkingdog 上把這個(gè)返回手勢開源摔桦,github地址社付,并果斷應(yīng)用到了百度知道 App 內(nèi)承疲,這是 Demo 效果:

利用了系統(tǒng)自己的邊緣返回手勢處理函數(shù)后,一切動畫和曲線都和原生效果一毛一樣了鸥咖。

于是乎發(fā)布了FDFullscreenPopGesture1.0 版本燕鸽,而且提供了一個(gè) AOP 形式的 API,把它添加到工程里面啼辣,什么代碼都不用寫啊研,所有 UINavigationController 就自帶這個(gè)全屏返回效果了。

絲滑的處理導(dǎo)航欄的顯示和隱藏

接下來我們發(fā)現(xiàn)利用系統(tǒng)的 UINavigationBar 時(shí)鸥拧,返回手勢中若碰到前一個(gè)頁面有 bar党远,后一個(gè)頁面沒 bar,或者反過來時(shí)富弦,動畫就非常難看沟娱,舉兩個(gè)反例:

手Q iOS:

它的個(gè)人中心頁面上面的 bar 是隱藏狀態(tài),然后做了個(gè)和其他頁面很像的假 bar腕柜,但返回手勢一開始就露餡了济似,為了彌補(bǔ),還做了下后面真 bar 的 alpha 值動畫盏缤,兩個(gè)返回按鈕還是重疊在了一起砰蠢。

新浪微博 iOS:

和手Q一樣的實(shí)現(xiàn)方式,只不過沒做 alpha 動畫唉铜,所以就非常明顯了台舱。

為啥會這樣呢?這可能就是 UINavigationController 在導(dǎo)航欄控制 API 上設(shè)計(jì)的缺陷了打毛。 一個(gè)

UINavigationController 管理了串行的 N 個(gè) UIViewController 棧式的 push 和 pop柿赊,而

UINavigationBar 由 UINavigationController 管理,這就導(dǎo)致了 UIViewController

無法控制自己上面的 bar 單獨(dú)的隱藏或顯示幻枉。 這非常像 UIApplication 全局的 status bar碰声,牽一發(fā)還得動全身,不過

Apple 在 iOS7 之后為 vc 控制自己的 status bar 提供了下面幾個(gè)方法:

- (UIStatusBarStyle)preferredStatusBarStyleNS_AVAILABLE_IOS(7_0);

- (BOOL)prefersStatusBarHiddenNS_AVAILABLE_IOS(7_0);

- (UIStatusBarAnimation)preferredStatusBarUpdateAnimationNS_AVAILABLE_IOS(7_0);

終于讓這個(gè)全局變量變成了局部變量熬甫,雖然寫起來費(fèi)勁了些胰挑。

但是對 UINavigationBar 的控制,依然是全局的椿肩,可能 Apple 覺得 App 不應(yīng)該有這種奇怪的頁面結(jié)構(gòu)瞻颂?

解決這個(gè)問題的方法也不難,在滑動返回的后要出現(xiàn)的那個(gè) view controller 中寫下面的代碼:

- (void)viewWillAppear:(BOOL)animated {

[superviewWillAppear:animated];

[self.navigationController setNavigationBarHidden:YESanimated:animated];

}

系統(tǒng)就會把有 bar 和 無 bar 的 transition 動畫銜接起來郑象。但是如上面所說贡这,這是個(gè)全局變量,還得在所有由這個(gè)沒有 bar

的特殊頁面能 push 和 pop 的頁面都進(jìn)行反向的處理厂榛,代碼非常的亂乎盖矫。于是乎丽惭,我們試著解決了這個(gè)問題,先看效果:

我特意挑了個(gè)從真 bar 到假 bar辈双,再從假 bar 到 真 bar 的頁面责掏,還算蠻絲滑的,transition 動畫全是系統(tǒng)自己搞定的湃望。

就事把FDFullscreenPopGesture更新到了 1.1 版本换衬,貫徹我們一向的精簡 API,你只需要在 bar 要隱藏的 view controller 中寫一句話:

- (void)viewDidLoad

[superviewDidLoad];

self.navigationController.fd_prefersNavigationBarHidden =YES;

}

或者喜歡重載的寫法也行:

- (BOOL)fd_prefersNavigationBarHidden {

returnYES;

}

刻意的模仿了下系統(tǒng)的命名風(fēng)格证芭,就這一句話瞳浦,剩下的就都不用操心了。

關(guān)于私有API

大家會質(zhì)疑說废士,這用到了 UIKit 的私有屬性和私有 API术幔,要是系統(tǒng)升級變了咋辦?要是審核被拒了咋辦湃密?

首先诅挑,iOS 系統(tǒng)的 SDK 為了向下兼容,一般只會增加方法或者修改方法實(shí)現(xiàn)泛源,不太可能直接刪除一個(gè)共有方法拔妥,而私有方法的行為確實(shí)可能有變化,但系統(tǒng) release 頻率畢竟很低达箍,每當(dāng)新版本發(fā)布時(shí) check 下原來的功能是否能 work 就好了没龙,大可不必?fù)?dān)心這么遠(yuǎn),SDK 是死的人是活的缎玫。

另一個(gè)就是審核問題硬纤,F(xiàn)DFullscreenPopGesture 的實(shí)現(xiàn)中有主要有兩處觸碰到了私有 API:

// 1. 私有變量標(biāo)志transition動畫是否正在進(jìn)行

[self.navigationController valueForKey:@"_isTransitioning"];

// 2. 一個(gè)內(nèi)部的selector

NSSelectorFromString(@"handleNavigationTransition:");

不論是 kvc 還是 selector 反射,都是利用 objc runtime

完成的赃磨,而到了這一層筝家,真的就沒啥公有私有可言了。設(shè)想你就是開發(fā) Apple 私有 API 檢查工具的工程師邻辉,給你一個(gè) ipa

的包岗憋,你會如何檢查出其中有沒有私有 API 呢银舱?

首先开睡,這個(gè)檢查一定是個(gè)靜態(tài)檢查吧而柑,不可能是運(yùn)行時(shí)檢查,因?yàn)榇a邏輯那么復(fù)雜吱瘩,把程序跑起來看所有 objc_msgSend 中包不包括私有調(diào)用這件事太不現(xiàn)實(shí)了道伟。

對 ipa 文件做靜態(tài)檢查的話肯定是去分析 Mach-O 可執(zhí)行文件,因?yàn)檫@時(shí)很多源代碼級別的信息已經(jīng)丟失使碾,經(jīng)分析可以采取下面幾種手段:

是否 link 了私有 framework 或者公開 framework 中的私有符號蜜徽,這可以防止開發(fā)者把私有 header 都 dump 出來供程序直接調(diào)用裹芝。

同上,使用@selector(_private_sel)加上-performSelector:的方式直接調(diào)用私有 API娜汁。

掃描所有符號,查看是否有繼承自私有類兄朋,重載私有方法掐禁,方法名是否有重合。

掃描所有string颅和,看字符串常量段是否出現(xiàn)和私有 API 對應(yīng)的傅事。

我覺得前三條被 catch 住的可能性最高,也最容易被檢查出來峡扩。再來看我們用到用字符串的方法 kvc 和 反射 selector蹭越,應(yīng)該屬于最后一條,這時(shí)候就很難抉擇了教届,拿handleNavigationTransition:來說响鹃,看上去人畜無害啊,我自己類里面的方法也完全可能命名出這個(gè)來案训,所以單單憑借字符串命中私有 API 判定买置,蘋果很容易誤傷一大票開發(fā)者。

綜上强霎,我覺得使用字符串的方式使用私有 API 是相對安全的忿项,我們的 App 馬上要提交審核,如果過了幾天你還能讀到這段文字城舞,說明我的猜想是木有錯(cuò)的轩触,大家可以放心使用。

0 代碼的 Demo

還有一個(gè)有意思的事家夺,我們在 github 上的demo工程木有寫一行代碼脱柱,就實(shí)現(xiàn)了下面的效果:

工程長這個(gè)樣子,view controller 類也沒寫拉馋,為了體現(xiàn)FDFullscreenPopGesture的 AOP 性質(zhì):

頁面由 Storyboard 構(gòu)建:

而控制頁面隱藏 bar 的屬性也能用 Runtime Attributes 模擬調(diào)用:

這樣就完成了一個(gè)非常干凈的 Demo

加入到你的工程中

首先要求最低支持 iOS7褐捻,我想在 WWDC 2015 結(jié)束,iOS9 發(fā)布后椅邓,主流的 App 就都會 iOS7 起跳了柠逞。

依然是熟悉的 cocoapods 安裝:

pod 'FDFullscreenPopGesture', '~> 1.1'

要是沒有搜到就pod setup下。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末景馁,一起剝皮案震驚了整個(gè)濱河市板壮,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌合住,老刑警劉巖绰精,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件撒璧,死亡現(xiàn)場離奇詭異,居然都是意外死亡笨使,警方通過查閱死者的電腦和手機(jī)卿樱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來硫椰,“玉大人繁调,你說我怎么就攤上這事“胁荩” “怎么了蹄胰?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長奕翔。 經(jīng)常有香客問我裕寨,道長,這世上最難降的妖魔是什么派继? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任宾袜,我火速辦了婚禮,結(jié)果婚禮上驾窟,老公的妹妹穿的比我還像新娘试和。我一直安慰自己,他們只是感情好纫普,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布阅悍。 她就那樣靜靜地躺著,像睡著了一般昨稼。 火紅的嫁衣襯著肌膚如雪节视。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天假栓,我揣著相機(jī)與錄音寻行,去河邊找鬼。 笑死匾荆,一個(gè)胖子當(dāng)著我的面吹牛拌蜘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播牙丽,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼简卧,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了烤芦?” 一聲冷哼從身側(cè)響起举娩,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后铜涉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體智玻,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年芙代,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吊奢。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,789評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡纹烹,死狀恐怖页滚,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情滔韵,我是刑警寧澤,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布掌实,位于F島的核電站陪蜻,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏贱鼻。R本人自食惡果不足惜宴卖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望邻悬。 院中可真熱鬧症昏,春花似錦、人聲如沸父丰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蛾扇。三九已至攘烛,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間镀首,已是汗流浹背坟漱。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留更哄,地道東北人芋齿。 一個(gè)月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像成翩,于是被迫代替她去往敵國和親觅捆。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評論 2 351

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

  • 來源:blog.sunnyxx.com/2015/06/07/fullscreen-pop-gesture/ 全屏...
    看之學(xué)之閱讀 470評論 0 0
  • 全屏返回手勢 本文章摘自于:一個(gè)絲滑的全屏滑動返回手勢 自 iOS7 之后麻敌,Apple 增加了屏幕邊緣右劃返回交互...
    許威彬閱讀 2,145評論 4 9
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫惠拭、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,066評論 4 62
  • 輕輕提筆 寫下與你滿心歡喜 微微白頭 認(rèn)真與你攜手到老
    張軒軒呢閱讀 289評論 2 0
  • 醫(yī)生有三重境界,第一重叫治病救人职辅,你能夠看好病人的疾病棒呛,這只能說明你是一個(gè)醫(yī)務(wù)工作者,一個(gè)技工域携,和修鞋匠簇秒、賣饅頭發(fā)...
    柳葉刀zhao閱讀 2,354評論 0 2