一個絲滑的全屏滑動返回手勢

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

全屏返回手勢

自 iOS7 之后,Apple 增加了屏幕邊緣右劃返回交互的支持,再配合上 UINavigationController 的交互式動畫,pop 到上一級頁面的操作變的非常順暢和絲滑,從此,我很少再使用點擊左上角導航欄上的返回按鈕的方式返回了,因為這對單手操作十分不友好;如果一個 App 居然膽敢不支持滑動返回,那離被卸載就不遠了。

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

FDFullscreenPopGesture

工作畢竟是工作,于是乎所以就被迫實現了套 pan 手勢處理加截圖和視差,雖然在運動曲線上、bar 截圖處理上下了不少功夫,但距離系統的絲滑效果還是差距挺遠。隨時間推移,終于能夠最低支持 iOS7 后,我們把這個問題再次拿出來討論和研究,直到在微博上看到了J_雨同學的這篇文章后才找到了這個迄今為止最簡單的解決方案。于是乎在他的授權下,我們在 forkingdog 上把這個返回手勢開源,github地址,并果斷應用到了百度知道 App 內,這是 Demo 效果:

利用了系統自己的邊緣返回手勢處理函數后,一切動畫和曲線都和原生效果一毛一樣了。

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

絲滑的處理導航欄的顯示和隱藏

接下來我們發現利用系統的 UINavigationBar 時,返回手勢中若碰到前一個頁面有 bar,后一個頁面沒 bar,或者反過來時,動畫就非常難看,舉兩個反例:

手Q iOS:

它的個人中心頁面上面的 bar 是隱藏狀態,然后做了個和其他頁面很像的假 bar,但返回手勢一開始就露餡了,為了彌補,還做了下后面真 bar 的 alpha 值動畫,兩個返回按鈕還是重疊在了一起。

新浪微博 iOS:

和手Q一樣的實現方式,只不過沒做 alpha 動畫,所以就非常明顯了。

為啥會這樣呢?這可能就是 UINavigationController 在導航欄控制 API 上設計的缺陷了。 一個

UINavigationController 管理了串行的 N 個 UIViewController 棧式的 push 和 pop,而

UINavigationBar 由 UINavigationController 管理,這就導致了 UIViewController

無法控制自己上面的 bar 單獨的隱藏或顯示。 這非常像 UIApplication 全局的 status bar,牽一發還得動全身,不過

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

- (UIStatusBarStyle)preferredStatusBarStyleNS_AVAILABLE_IOS(7_0);

- (BOOL)prefersStatusBarHiddenNS_AVAILABLE_IOS(7_0);

- (UIStatusBarAnimation)preferredStatusBarUpdateAnimationNS_AVAILABLE_IOS(7_0);

終于讓這個全局變量變成了局部變量,雖然寫起來費勁了些。

但是對 UINavigationBar 的控制,依然是全局的,可能 Apple 覺得 App 不應該有這種奇怪的頁面結構?

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

- (void)viewWillAppear:(BOOL)animated {

[superviewWillAppear:animated];

[self.navigationController setNavigationBarHidden:YESanimated:animated];

}

系統就會把有 bar 和 無 bar 的 transition 動畫銜接起來。但是如上面所說,這是個全局變量,還得在所有由這個沒有 bar

的特殊頁面能 push 和 pop 的頁面都進行反向的處理,代碼非常的亂乎。于是乎,我們試著解決了這個問題,先看效果:

我特意挑了個從真 bar 到假 bar,再從假 bar 到 真 bar 的頁面,還算蠻絲滑的,transition 動畫全是系統自己搞定的。

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

- (void)viewDidLoad

[superviewDidLoad];

self.navigationController.fd_prefersNavigationBarHidden =YES;

}

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

- (BOOL)fd_prefersNavigationBarHidden {

returnYES;

}

刻意的模仿了下系統的命名風格,就這一句話,剩下的就都不用操心了。

關于私有API

大家會質疑說,這用到了 UIKit 的私有屬性和私有 API,要是系統升級變了咋辦?要是審核被拒了咋辦?

首先,iOS 系統的 SDK 為了向下兼容,一般只會增加方法或者修改方法實現,不太可能直接刪除一個共有方法,而私有方法的行為確實可能有變化,但系統 release 頻率畢竟很低,每當新版本發布時 check 下原來的功能是否能 work 就好了,大可不必擔心這么遠,SDK 是死的人是活的。

另一個就是審核問題,FDFullscreenPopGesture 的實現中有主要有兩處觸碰到了私有 API:

// 1. 私有變量標志transition動畫是否正在進行

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

// 2. 一個內部的selector

NSSelectorFromString(@"handleNavigationTransition:");

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

完成的,而到了這一層,真的就沒啥公有私有可言了。設想你就是開發 Apple 私有 API 檢查工具的工程師,給你一個 ipa

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

首先,這個檢查一定是個靜態檢查吧,不可能是運行時檢查,因為代碼邏輯那么復雜,把程序跑起來看所有 objc_msgSend 中包不包括私有調用這件事太不現實了。

對 ipa 文件做靜態檢查的話肯定是去分析 Mach-O 可執行文件,因為這時很多源代碼級別的信息已經丟失,經分析可以采取下面幾種手段:

是否 link 了私有 framework 或者公開 framework 中的私有符號,這可以防止開發者把私有 header 都 dump 出來供程序直接調用。

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

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

掃描所有string,看字符串常量段是否出現和私有 API 對應的。

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

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

0 代碼的 Demo

還有一個有意思的事,我們在 github 上的demo工程木有寫一行代碼,就實現了下面的效果:

工程長這個樣子,view controller 類也沒寫,為了體現FDFullscreenPopGesture的 AOP 性質:

頁面由 Storyboard 構建:

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

這樣就完成了一個非常干凈的 Demo

加入到你的工程中

首先要求最低支持 iOS7,我想在 WWDC 2015 結束,iOS9 發布后,主流的 App 就都會 iOS7 起跳了。

依然是熟悉的 cocoapods 安裝:

pod 'FDFullscreenPopGesture', '~> 1.1'

要是沒有搜到就pod setup下。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,527評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,687評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,640評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,957評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,682評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,011評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,009評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,183評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,714評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,435評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,665評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,148評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,838評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,251評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,588評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,379評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,627評論 2 380

推薦閱讀更多精彩內容

  • 來源:blog.sunnyxx.com/2015/06/07/fullscreen-pop-gesture/ 全屏...
    看之學之閱讀 487評論 0 0
  • 全屏返回手勢 本文章摘自于:一個絲滑的全屏滑動返回手勢 自 iOS7 之后,Apple 增加了屏幕邊緣右劃返回交互...
    許威彬閱讀 2,179評論 4 9
  • 發現 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,179評論 4 61
  • 輕輕提筆 寫下與你滿心歡喜 微微白頭 認真與你攜手到老
    張軒軒呢閱讀 292評論 2 0
  • 醫生有三重境界,第一重叫治病救人,你能夠看好病人的疾病,這只能說明你是一個醫務工作者,一個技工,和修鞋匠、賣饅頭發...
    柳葉刀zhao閱讀 2,362評論 0 2