iPad 多工 Spilt View & Size Class
[https://www.cnblogs.com/smileEvday/p/SpiltView_SizeClass.html]
一、多工簡介
iOS 9 以後iPad新增了多工的支援,主要形式有三種:
- Slide Over (側邊快捷開啟)
- Spilt View (多工分屏)
- Picture in Picture (畫中畫)
1. Picture in Picture
使用系統AVKit或者AVFoundation庫提供的新的API替換掉老的 MPMoviePlayerViewController, MPMoviePlayerViewController,做一些調整即可。
2. Slide Over
Slide Over支援起來比較簡單,程式基本上不需要做任何程式碼級別的適配。
Tips: App互動設計的時候,應該避免採用螢幕右側向左滑這一類的互動。因為iOS9以後系統攔截了該事件用來觸發Slide Over & Spilt View。
例如網易新聞iPad端的評論劃出功能
3. Spilt View
多工分屏功能,我們今天主要探討的內容,後續章節有詳細描述。
二、是否要支援多工分屏?
1. 是否需要適配
引用官方的說法
Adopt Slide Over and Split View unless you have a specific reason not to. From a customer’s perspective, an iOS 9 app that doesn’t adopt Slide Over and Split View feels out of place.
簡單翻譯一下:“最好新增Slide Over & Spilt View的適配,除非你有足夠的原因。不做新特性的適配會讓使用者覺得你的程式out了”
當然也有例外的情況,如果你的程式屬於以下兩種,那麼不需要去做多工的適配:
- 以拍照為主要功能的程式
- 需要全屏互動的程式,例如需要使用到感測器的遊戲類應用
2. 如何禁用多工分屏
要禁掉App的多工分屏支援,只需要在App的info.plist中新增一個“UIRequiresFullScreen”的key,設定value為“YES”即可。
到這兒了,如果你的不需要支援多工分屏的話那麼就後面的內容就可以跳過了。
三. 適配前需要明確的幾個點
1. 轉變觀念
首先有一個觀念我們得轉變過來,同一時刻執行在前臺的App不再限制為一個。如果使用者進入了多工分屏模式的話,那麼就會有兩個App同時執行在前臺。
Both Apps in Spilt View are running in the foreground.
雖然兩個App同時執行在前臺時,地位卻不一樣,Primary(老大,通常在左邊)和Secondary(老二,通常指的是右邊的應用)。
只有老大:
- 擁有狀態列的控制許可權
- 可以處理外接螢幕的顯示(通常使用UIScreen實現)
- 可以顯示畫中畫視窗
- 可以佔據2/3寬的螢幕,而老二最多隻能佔據螢幕寬度的一半
避免使用UIScreen的bounds來處理App應該的展示區域,最好使用UIWindow的bounds來代替。
因為在多工分屏下UIScreen還是那個Screen,只不過App的keyWindow不再時時刻刻充滿UIScreen了,顯示在什麼位置,顯示多大面積,全部取決於使用者使用裝置的姿勢。
2. 面臨的問題
前面提到過了,當進入多工分屏模式以後,將會有兩個App同時執行在前臺。試想有兩個App同時需要使用CPU,GPU,記憶體,I/O及其它的硬體資源,要想保持良好的使用者體驗,就需要我們對自己的App做很多效能調優的方面的工作。
關於效能調優方面的知識,可以參考:Adopting Multitasking Enhancements on iPad
Every iOS app—even one that opts out of using multitasking features—needs to operate as a good citizen in iOS 9.
Now, even full-screen apps don’t have exclusive use of screen real estate, the CPU, memory, or other resources.
同時蘋果基於保證使用者體驗的角度,對於支援做了硬體層面的限制如下:
前面提到了,Primary App比Secondary App擁有諸多優勢,但是有一點是一樣的:
當系統收到記憶體警告時,無論是Primary App還是Secondary App均可能被Kill掉
四. 如何適配Spilt View
如果遵循iOS 8引入的新的UI最佳實踐,那麼適配多工適配將會是一件很容易的實情。可是問題關鍵問題就出在了這個“如果”上。
iOS 8推出以後蘋果提的最多的“Adaptivity”,以及新引入了Size Class體系,並提出了讓我們忘記裝置方向的概念,所以的這一切都是在為了我們能夠方便的實現App的佈局。
通常開發App的UI框架的陳舊加上互動設計只考慮橫豎屏(甚至只考慮一個方向)導致了我們適配Spilt View的難度比較大。
1. 適配Spilt View的幾點要求
- Xcode 7 及之後編譯
- 使用iOS 9 及之後的SDK
使用"LaunchScreen.storyboard"代替launch.png之類的圖片,完成啟動畫面定製。Xcode7之後新建工程會自動幫忙建立該檔案並設定Info.plist,對於已存在的老工程需要我們手動建立該檔案,並在Info.plist中做相應配置。
PS. 蘋果要求LaunchScrenn.storyboard中必須使用Autolayout佈局,還在用全手寫佈局的朋友們,該考慮切換到Auto Layout佈局了。
支援四個方向
2. 多工分屏模式切換時發生了什麼
在多工分屏模式時,App展示的尺寸完全取決於使用者,可能會佔螢幕的3/10, 5/10, 7/10等,再加上豎屏時候那兩個奇葩的比例。一個App要完全支援iPad的多工分屏,如果使用硬編碼的方式,那麼需要考慮5套佈局,有沒有想死的感覺。
先彆著急,接著往下看。
當多工分屏模式下,使用者操作應用之間的分割區改變兩個應用的顯示比例時,系統會同時呼叫兩個App的“applicationWillResignActive”方法。然使用者完成操作的時候系統會再同時呼叫連個App的“applicationDidEnterBackground”方法。
關於如何相應App狀態變換,請看文件:Strategies for Handling App State Transitions
與此同時,系統會通過以下兩個方面告知我們分屏狀態的改變:
- Window尺寸的變化
- RootVC 的Size Class的變化
這兩個點配合起來才能完成多工分屏顯示模式切換的響應。
因為多工分屏顯示模式的變化並不總是伴隨著Size Class的變化,例如從3/10 --> 5/10的變換的時候水平方向的Size Class一直都是Compac模式,但是尺寸(寬度)卻發生了變化。
3. 如何響應Window尺寸變化
當Window尺寸變化時通常伴隨著VC的viewDidLayoutSubViews活著View的layOutSubViews方法的呼叫,我們可以在這些方法裡面重新計算位置,完成UI佈局的重新整理。
還有一個更好的方法就是Auto Layout,我們在程式一開始佈局的時候通過指定元素之間的約束來描述佈局,這樣在View的尺寸變化的時候系統會根據我們制定的約束條件自動完成佈局的重新整理。
4. 如何響應Size Class的變化
我是程式碼黨,介面佈局大部分都是靠程式碼實現,Storyboard幾乎不用。在一開始我查詢資料的時候一搜Size Class出來的都是教人怎麼在Storyboard中完成介面佈局的文章。還以為Size Class就是專門為Storyboard設計的。
後面在搜尋終於被我發現了一些端倪,iOS 8中 引入了兩個Protocol:UITraitEnvironment 和 UIContentContainer,以及一個類UITraitCollection。
其中UITraitEnvironment協議的定義如下:
/*! Trait environments expose a trait collection that describes their environment. */
@protocol UITraitEnvironment <NSObject>
@property (nonatomic, readonly) UITraitCollection *traitCollection NS_AVAILABLE_IOS(8_0);
/*! To be overridden as needed to provide custom behavior when the environment's traits change. */
- (void)traitCollectionDidChange:(nullable UITraitCollection *)previousTraitCollection NS_AVAILABLE_IOS(8_0);
@end
可以看到該協議定義了一個traitCollection的屬性,還有一個用來通知traitCollection改變的方法。系統中我們可以想到的UI類都實現了這個協議,包括: UIScreen, UIWindow, UIViewController, UIPresentationController, 以及UIView.
UIContentContainer協議則定義了幾個VC級別的用來響應TraitCollection變化的方法,UIViewController和UIPresentationController都實現了該協議。通過該協議定義的方法我們可以在Size Class變化的時候做一些動畫。
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator NS_AVAILABLE_IOS(8_0);
- (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator NS_AVAILABLE_IOS(8_0);
UITraitCollection類則定義了一些屬性用來描述裝置特性,如下所示:
horizontalSizeClass
verticalSizeClass
displayScale
userInterfaceIdiom
forceTouchCapability
到這兒我們終於看見了SizeClass的身影了,而Size Class的定義如下:
typedef NS_ENUM(NSInteger, UIUserInterfaceSizeClass) {
UIUserInterfaceSizeClassUnspecified = 0,
UIUserInterfaceSizeClassCompact = 1,
UIUserInterfaceSizeClassRegular = 2,
} NS_ENUM_AVAILABLE_IOS(8_0);
iOS 系統把UI的顯示模式抽象為三種:Unspecified(對應StoryBoard中的any),Compact,Regular。
非多工分屏下,常見裝置的Size Class如下:
可以看出在非多工分屏模式下,iPad 無論在橫屏和豎屏下寬,高都是Regular。
進入多工分屏模式以後Size Class如下:
搞懂了Size Class的知識以後,我們再看看Size Class變換的時候我們可以做些什麼呢?
- 改變SubViews的尺寸和位置
- 新增或者移除subView
- 新增,移除或者修改約束(注:約束只能修改constant)
- 改變UILabel,TextField,Text view等的字型大小
五. Demo
我寫了一個適陪Spilt View多工分屏的Demo,地址:SpiltViewDemo,App的內容很簡單,介面上只包含兩個元素一個ImageView用來展示圖片,一個UITextView用來展示文字描述。
截圖如下:
在Regular模式下圖文結構為左右結構,當進入到Compact模式時切換為上下結構。
核心的程式碼如下:
#pragma mark -
#pragma mark Size Class Related
- (void)updateConstraintsForSizeClass:(UIUserInterfaceSizeClass)newSizeClass
{
NSArray *currentConstraints = [self constraintsForSizeClass:self.traitCollection.horizontalSizeClass];
NSArray *newConstraints = [self constraintsForSizeClass:newSizeClass];
[self.view removeConstraints:currentConstraints];
[self.view addConstraints:newConstraints];
if (newSizeClass == UIUserInterfaceSizeClassRegular) {
_imageIV.image = [UIImage imageNamed:@"aodi.jpg"];
_textView.font = [UIFont systemFontOfSize:24];
_textView.text = _aodiDes;
}
else {
_imageIV.image = [UIImage imageNamed:@"aotuo.jpg"];
_textView.font = [UIFont systemFontOfSize:16];
_textView.text = _aodiDes;
}
[self.view updateConstraintsIfNeeded];
}
- (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
[super willTransitionToTraitCollection:newCollection withTransitionCoordinator:coordinator];
[self updateConstraintsForSizeClass:newCollection.horizontalSizeClass];
}
可以看到只是簡單的在willTransitionToTraitCollection:withTransitionCoordinator:方法中檢測Size Class的變化,然後跟新約束系統即可。
當然實際應用在適配Spilt View的時候工作量可能遠比這個多,但是原理都是一樣的。
實際應用適配Spilt View除了技術上的支援,我想更多地是互動和視覺的調整,在多工模式切換的時候如何更合理的調整元素的擺放位置以及互動的方式。
六. 總結 & 思考
1. 向下相容
Size Class是iOS 8才引入的概念,如果你也像我一樣使用手寫的方式寫介面,且你的應用還需要支援iOS 7,那麼需要小心行事。
如果你的應用使用Storyboard的方式使用Size Class,那麼恭喜你只要你符合以下幾點要求,那麼系統會自動幫你做向下相容。
- 使用Xcode6及以後編譯
- 豎直方向的Size Class不是Compact模式
Important: Compatibility occurs at build time, not at run time.
2. 關於效能
在最後還是要提一下App的效能,作為一個iOS上的好公民,我們需要多花一些精力來做App的效能調優,用好Profile工具,仔細查詢並優化App在CPU,GPU,memory,I/O等方面的佔用。
3. 及時跟進iOS的新技術
及時跟進iOS的新技術,這樣在出現新特性的時候才能快速方便的接入。仔細想想從iOS 6的Auto Layout, iOS8 的Size Class,再到iOS 9推出的Spilt View,整個發展的遞進式的。
4. 參考資料
Adopting Multitasking Enhancements on iPad
Size Classes Design Help
Strategies for Handling App State Transitions
UITraitEnvironment
UIContentContainer
UITraitCollection
Building Adaptive Apps with UIKit
注:smileEvday保留本文的一切權利,轉載請著名原文出處
本文所有內容僅代表個人觀點,如有有不對的地方,歡迎指出。
相關文章
- PARTITION SPILT
- 不同size class顯示不同的UIUI
- 蘋果為搭載iOS 8的iPad推出分屏多工功能蘋果iOSiPad
- iOS 9 分屏多工(2):Slide Over & Split View快速入門iOSIDEView
- iPad keyboard will not dismiss if modal view controller presentation style is UIModalPresentationForiPadViewControllerUI
- 多工原理
- iOS:iOS8開發storyboard中autolayout和size class的使用詳解 (2)iOS
- swift2.0實現String.spilt()方法Swift
- android自定義View “android.view.InflateException: Binary XML file line # : Error inflating class"AndroidViewExceptionXMLError
- Javascript 之中的 class/建構函式/工廠函式JavaScript函式
- iOS 7 多工管理iOS
- 對Maxvalue上限範圍分割槽進行spilt操作
- Error inflating class com.facebook.drawee.view.SimpleDraweeView問題的解決ErrorView
- 多工處理方式之一:多程式
- 多執行緒實現多工二執行緒
- 多執行緒實現多工一執行緒
- JPTagView-多樣化的標籤ViewView
- 多View統一Camera v1.2View
- 多工同步與互斥概念
- 架構學習-多工架構
- Zite:研究發現人們白天使用iPhone多 夜晚用iPad多iPhoneiPad
- 並行多工學習論文閱讀(一):多工學習速覽並行
- Python中的多工:多執行緒Python執行緒
- Size DatabaseDatabase
- 關於GCD多工處理GC
- python多工抓取圖片Python
- PHP 多工協程處理PHP
- 【譯】Async/Await(一)——多工AI
- 多工處理方式之二:多執行緒執行緒
- JSRE中的多工與多執行緒JS執行緒
- DB_BLOCK_SIZE and DB_CACHE_SIZE in OracleBloCOracle
- 《福布斯》:不該給員工配iPad的七大理由iPad
- 同一個元素中有多個class,優先順序
- mixin配合class實現多繼承的絕佳妙用繼承
- 加個touch ID多七百塊 iPad Mini 3評測iPad
- ORA-27046: file size is not a multiple of logical block sizeBloC
- sort_area_retained_size與sort_area_sizeAI
- python--多工執行緒Python執行緒