iOS-3D Touch 特性 & API 詳解

前言

關(guān)于這篇文章

由于iPhone 6S發(fā)布不到一年的時(shí)間,很多新特性、新技術(shù)還未普遍,不管是3D Touch的使用還是開發(fā),對其有相關(guān)了解的人并不多。前幾天偶然接觸了3D Touch的某個(gè)API接口,為了滿足好奇心,于是我就系統(tǒng)地去了解了這個(gè)蘋果的新技術(shù)。查閱了相關(guān)的官方文檔,敲了些Demo,并編寫了這篇文章,作為總結(jié)。

從Force Touch到3D Touch

使用過新版Mac Book或Apple Watch的朋友應(yīng)該對Force Touch這個(gè)詞匯并不陌生,這是蘋果針對設(shè)備觸控操作的一項(xiàng)新的技術(shù),將傳統(tǒng)的用戶觸控點(diǎn)擊操作擴(kuò)展化,加上了按壓操作,設(shè)備可根據(jù)用戶手指在屏幕上的按壓力度來進(jìn)行相應(yīng)的響應(yīng)。在新版Mac Book以及Apple Watch中,我們可以通過使用不同的力度按壓觸控板或觸控屏來調(diào)出更多的控制選項(xiàng),人機(jī)交互性非常高。
3D TouchForce Touch延伸出的新一代技術(shù),它現(xiàn)在應(yīng)用于裝配了iOS9以上操作系統(tǒng)的iPhone 6S上,致力于向iPhone用戶提供更加高質(zhì)量的交互體驗(yàn),將操作方式擴(kuò)展至三維層面。

本篇文章分別針對3D Touch的特性以及開發(fā)API進(jìn)行講解。

特性 — 3D Touch On iPhone

Home Screen Quick Actions - 主頁屏幕快速操作

在手機(jī)的主頁上,假如你用手指輕輕按壓某個(gè)應(yīng)用的圖標(biāo),圖標(biāo)的背后出現(xiàn)了一個(gè)半透明的矩形,這就說明了這款應(yīng)用支持Home Screen Quick Actions(主頁屏幕快速操作)。這時(shí),我們保持手指按壓,并加大力度,你就會(huì)發(fā)現(xiàn)這個(gè)應(yīng)用圖標(biāo)的周圍都變模糊了,一個(gè)小巧的選項(xiàng)欄菜單在你眼前彈出。


這個(gè)選項(xiàng)欄菜單每個(gè)選項(xiàng)視圖最多允許有兩行文本(主文本、次文本)以及一個(gè)圖標(biāo)(可要可不要)。另外,圖標(biāo)的位置是不定的,它會(huì)在文本的左邊或者右邊進(jìn)行布局,具體放置于哪一邊,則根據(jù)應(yīng)用圖標(biāo)的水平位置而定,不過這些布局系統(tǒng)都已經(jīng)幫我們處理好了。
當(dāng)我們點(diǎn)擊某一個(gè)選項(xiàng),應(yīng)用程序就會(huì)運(yùn)行起來,并且執(zhí)行相應(yīng)的操作,相比于以往用戶要先進(jìn)入應(yīng)用程序才能再進(jìn)行操作,使用Home Screen Quick Actions則更加的便利。

Peek and Pop - 預(yù)覽和查看詳情

Peek - 預(yù)覽

在傳統(tǒng)的手機(jī)用戶操作中,當(dāng)我們在應(yīng)用里看到某張縮略圖、某個(gè)網(wǎng)址鏈接或者某個(gè)列表Item時(shí),若我們想查看詳細(xì)的信息,比如想看縮略圖對應(yīng)的大圖、網(wǎng)址鏈接對應(yīng)的網(wǎng)頁、Item對應(yīng)的詳情頁面,一般會(huì)用手指對屏幕進(jìn)行點(diǎn)擊操作,從而讓應(yīng)用的頁面進(jìn)行跳轉(zhuǎn)。新特性Peek則大大提高了這類型操作的用戶體驗(yàn)。

Peek演示

上方效果圖所展示的是對一個(gè)縮略圖片進(jìn)行Peek操作,當(dāng)我們用手指輕壓圖片時(shí),圖片的周圍迅速模糊,這說明你所按壓的地方支持Peek操作。按壓力度稍微增大,預(yù)覽圖就出來了,這就是Peek(預(yù)覽)功能。當(dāng)我們將手指從屏幕上抬起時(shí),預(yù)覽圖就會(huì)消失,界面也就恢復(fù)回來。
有了Peek的操作簡化,當(dāng)我們想預(yù)覽某些詳情時(shí),只需按壓屏幕,手機(jī)即可彈出詳情頁面;移開手指,界面恢復(fù)原狀,這樣就使得用戶不必進(jìn)入一個(gè)新的頁面瀏覽詳情,然后再點(diǎn)擊返回按鈕回到原來視圖了。


Peek quick actions - 預(yù)覽中的快速操作

上方已經(jīng)說到,當(dāng)我們的手指按壓需要預(yù)覽的屏幕的區(qū)域,預(yù)覽的視圖就會(huì)出現(xiàn)。現(xiàn)在,繼續(xù)保持手指的按壓狀態(tài),然后再向上方滑動(dòng),就會(huì)在預(yù)覽視圖的下方滑出一個(gè)選項(xiàng)欄菜單。



當(dāng)菜單完全顯示出來后,你可以松開按壓在屏幕上的手指,然后點(diǎn)擊相應(yīng)的選項(xiàng)來執(zhí)行操作,就像上方效果圖一樣,可以復(fù)制、分享、點(diǎn)贊、刪除等等。


Pop - 查看詳情

在能出現(xiàn)Peek預(yù)覽視圖的手指按壓力度基礎(chǔ)上,用戶再使把勁加大點(diǎn)力度,就能進(jìn)入相關(guān)詳情頁面,這個(gè)就是Pop。事實(shí)上,Pop所進(jìn)入的詳情頁面跟用戶用手指輕點(diǎn)后所跳轉(zhuǎn)出來的頁面是一樣的,所以,用戶如果想直接進(jìn)入詳情頁面,不需要預(yù)覽,可以直接輕點(diǎn)屏幕指定區(qū)域即可;而在預(yù)覽中,用戶想了解得更多,可以再加大按壓力度進(jìn)入詳情頁面。

3D Touch 還能做些什么?

3D Touch能完成的功能非常多,你可以利用它來制作一個(gè)繪畫板,根據(jù)手指在屏幕上的壓力大小來模擬畫筆的粗細(xì),你也可以做一款精美的手游,通過手指的按壓力度來反饋不同的游戲操作......
總之,3D Touch非常的強(qiáng)大,潛力無限。??

開發(fā) — 3D Touch API

下面,我會(huì)通過蘋果提供的3D TouchAPI就之前所提及到的各個(gè)3D Touch特性進(jìn)行開發(fā)實(shí)現(xiàn)的分析。所有的交互跟視圖布局我都是使用純代碼去實(shí)現(xiàn)。

判斷設(shè)備是否支持3D Touch

我們在為應(yīng)用添加3D Touch功能時(shí),有必要做設(shè)備是否支持或開啟3D Touch的判斷,考慮到用戶使用的手機(jī)型號(hào)比iPhone 6s低,或者用戶自己已經(jīng)手動(dòng)關(guān)閉了3D Touch功能,所以在編寫代碼的時(shí)候,需要獲取或監(jiān)聽當(dāng)前設(shè)備針對于3D Touch的可用性狀態(tài),以便在后面做出判斷。

我們獲取當(dāng)前設(shè)備針對于3D Touch的可用性狀態(tài),可以使用協(xié)議UITraitEnvironment

UITraitEnvironment的結(jié)構(gòu)

UITraitEnvironment中包含一個(gè)屬性以及一個(gè)方法:

  • var traitCollection: UITraitCollection
  • func traitCollectionDidChange(previousTraitCollection: UITraitCollection?)

不管是屬性還是方法,其目的都是讓我們能夠獲取到當(dāng)前的設(shè)備特征環(huán)境集合,只不過使用方法來獲取比較動(dòng)態(tài),可以時(shí)刻監(jiān)聽變化。

獲取到的環(huán)境集合為UITraitCollection類型,這個(gè)類里面包含屬性forceTouchCapability,是一個(gè)UIForceTouchCapability枚舉類型,有三個(gè)case,分別是Unknown(未知的)、Unavailable(不可用的)、Available(可用的),根據(jù)相應(yīng)的forceTouchCapability值,我們就能知道當(dāng)前設(shè)備對3D Touch的可用性狀態(tài)。


如何使用UITraitEnvironment

其實(shí),很多我們常用的類都已經(jīng)實(shí)現(xiàn)了UITraitEnvironment協(xié)議,比如說UIViewUIViewController等等,我們可以直接從他們的內(nèi)部中獲得traitCollection屬性然后進(jìn)行判斷:

if self.traitCollection.forceTouchCapability == .Available {
    //  TODO:  加入實(shí)現(xiàn)3D Touch的代碼
}

如果我們想做到實(shí)時(shí)監(jiān)聽狀態(tài)的變化,比如軟件在運(yùn)行的時(shí)候用戶突然關(guān)閉了3D Touch,我們可以自己去實(shí)現(xiàn)UITraitEnvironment協(xié)議,實(shí)現(xiàn)其中的監(jiān)聽方法,在這里我就不演示代碼了。

Home Screen Quick Actions

實(shí)現(xiàn)Home Screen Quick Actions選項(xiàng)欄菜單

實(shí)現(xiàn)Home Screen Quick Actions有兩種方法,分別是static(靜態(tài))實(shí)現(xiàn)以及dynamic(動(dòng)態(tài))實(shí)現(xiàn),它們的實(shí)現(xiàn)主要都是依靠UIApplicationShortcutItem這個(gè)類來進(jìn)行。

  • Static 靜態(tài)實(shí)現(xiàn) 可以硬性地規(guī)定好要呈現(xiàn)出來的選項(xiàng)信息,這些設(shè)定好的選項(xiàng)在后期是不能夠再次修改的。進(jìn)行靜態(tài)實(shí)現(xiàn),我們需要修改的是Info.plist文件。下面我就編輯Info.plist文件來進(jìn)行靜態(tài)實(shí)現(xiàn):

    如圖所示,我在Info.plist文件中添加了一個(gè)key為UIApplicationShortcutItems的數(shù)組,里面有兩個(gè)字典類Item,每個(gè)字典類Item都代表了一個(gè)UIApplicationShortcutItem,它們具有5個(gè)屬性:

    • UIApplicationShortcutItemIconType (String) 選項(xiàng)的圖標(biāo)類型,可選擇性設(shè)置。使用static靜態(tài)實(shí)現(xiàn)是無法使用自己定義的圖標(biāo)的,不過系統(tǒng)也已經(jīng)提供好一些默認(rèn)的圖標(biāo),我們可以設(shè)置圖標(biāo)的類型來使用指定的系統(tǒng)默認(rèn)圖標(biāo)。那究竟有多少種圖標(biāo)類型呢?這個(gè)我放在后面講~

    • UIApplicationShortcutItemTitle (String) 選項(xiàng)的主標(biāo)題,必要設(shè)置項(xiàng)。相對于次標(biāo)題,主標(biāo)題文字較大且顏色較深,位于次標(biāo)題的上方。

    • UIApplicationShortcutItemSubtitle (String) 選項(xiàng)的次標(biāo)題,可選擇性設(shè)置。主要起到選項(xiàng)的幫助提示作用。

    • UIApplicationShortcutItemType (String) 選項(xiàng)的類型,必要設(shè)置項(xiàng)。利用它,我們就可以在你點(diǎn)擊選項(xiàng)執(zhí)行handle語句時(shí)判別具體是哪一個(gè)選項(xiàng)被選中了,從而讓程序進(jìn)行相應(yīng)的操作。關(guān)于選項(xiàng)選擇后的反饋處理,我在后面也會(huì)詳細(xì)去講。

    • UIApplicationShortcutItemUserInfo (Dictionary) 附加信息,可選擇性設(shè)置。你可以在里面添加某些附加信息,在執(zhí)行handle語句的時(shí)候可提取出來,具體看你的操作邏輯是如何實(shí)現(xiàn)的了。

      現(xiàn)在我把應(yīng)用跑起來后,回到手機(jī)的主頁面,并用力按壓此應(yīng)用的圖標(biāo),Home Screen Quick Actions的選項(xiàng)欄菜單就呈現(xiàn)在我們的眼前:


  • Dynamic 動(dòng)態(tài)實(shí)現(xiàn) 較為靈活,我們通過代碼去構(gòu)建每個(gè)選項(xiàng),所以,在程序運(yùn)行的過程中,選項(xiàng)的信息可以動(dòng)態(tài)地去改變,不過,動(dòng)態(tài)實(shí)現(xiàn)較靜態(tài)實(shí)現(xiàn)來說相對復(fù)雜了點(diǎn)。

    enum ShortcutItemType: String {
        case Home
        case Share
    }
    
    func setupShortcutItemsWithApplication(application: UIApplication) {
        let playItem = UIApplicationShortcutItem(type: ShortcutItemType.Home.rawValue, localizedTitle: "主頁", localizedSubtitle: "點(diǎn)擊進(jìn)入應(yīng)用主頁", icon: UIApplicationShortcutIcon(templateImageName: "icon_home"), userInfo: nil)
        let shareItem = UIApplicationShortcutItem(type: ShortcutItemType.Share.rawValue, localizedTitle: "分享", localizedSubtitle: "點(diǎn)擊向朋友分享", icon: UIApplicationShortcutIcon(type: .Share), userInfo: nil)
        application.shortcutItems = [playItem, shareItem]
    }
    

    如代碼所示,應(yīng)用的單例application對象中擁有shortcutItems屬性,這是一個(gè)數(shù)組對象,我們可以在里面添加UIApplicationShortcutItem實(shí)例或可變UIMutableApplicationShortcutItem實(shí)例,從而實(shí)現(xiàn)菜單中的每個(gè)選項(xiàng)。
    這里值得注意的是,要在shortcutItem上配置icon并不是用到簡單的UIImage類,而是使用專門的UIApplicationShortcutIcon,它有兩種構(gòu)造方式,一種是選擇一個(gè)類型,然后使用與類型相對應(yīng)的系統(tǒng)所提供的圖標(biāo),究竟有多少種類型呢?我下面來列舉一下:

    UIApplicationShortcutIconType 枚舉:
    
    iOS 9.0 及以上系統(tǒng)所支持:
    case Compose
    case Play
    case Pause
    case Add
    case Location
    case Search
    case Share
    
    iOS 9.1 及以上系統(tǒng)所支持:
    case Prohibit
    case Contact
    case Home
    case MarkLocation
    case Favorite
    case Love
    case Cloud
    case Invitation
    case Confirmation
    case Mail
    case Message
    case Date
    case Time
    case CapturePhoto
    case CaptureVideo
    case Task
    case TaskCompleted
    case Alarm
    case Bookmark
    case Shuffle
    case Audio
    case Update
    

    構(gòu)造的另一種方式是填入一串字符串,其實(shí)就是圖片的名字,對于這張圖片,蘋果做出了以下的要求:

    1. 這張圖片必須位于你的應(yīng)用程序包(app bundle)中。
    2. 圖片要為正方形,顏色使用單色,大小為35×35 points(點(diǎn))。系統(tǒng)為了保持UI的統(tǒng)一性,會(huì)將你提供的這張圖片進(jìn)行顏色渲染,最終圖片的整體顏色會(huì)變?yōu)榛液谏赃@里建議圖片使用單色,即只有一種顏色。

    現(xiàn)在我們在AppDelegate中的application(_:, didFinishLaunchingWithOptions:)方法里面執(zhí)行setupShortcutItemsWithApplication(_:),把a(bǔ)pplication作為參數(shù)傳入其中。
    這里提供一部分的參考代碼:

    if let shortcutItems = application.shortcutItems where shortcutItems.isEmpty {
            setupShortcutItemsWithApplication(application)
        }
    

    可能有人在這里會(huì)感到奇怪,為什么我在執(zhí)行setupShortcutItemsWithApplication(_:)方法前要先判斷application中的shortcutItems數(shù)組屬性是否為空容器(里面沒有對象),原因是當(dāng)我們第一次開啟這個(gè)應(yīng)用的時(shí)候,系統(tǒng)會(huì)將我們應(yīng)用所配置的所有shortcutItem進(jìn)行記錄,在我們下一次打開應(yīng)用時(shí),我們不必再去配置一遍,也就是說,application中的shortcutItems屬性在應(yīng)用第一次打開的時(shí)候是空的,但是當(dāng)我們進(jìn)行相應(yīng)的配置后,在下一次的應(yīng)用開啟時(shí),shortcutItems就會(huì)默認(rèn)被系統(tǒng)所賦值,我們也沒必要每次打開應(yīng)用都去配置它。

    現(xiàn)在,運(yùn)行程序,我們來測試一下:


    在程序運(yùn)行的過程中,我們可以任意改變shortcutItems

    UIApplication.sharedApplication().shortcutItems = dynamicShortcuts
    
  • static與dynamic混用共同實(shí)現(xiàn)Home Screen Quick Actions 時(shí),選項(xiàng)欄菜單中各個(gè)選項(xiàng)的順序是按照先靜態(tài)后動(dòng)態(tài)來排列的。此外,我們還要注意避免選項(xiàng)類型的沖突。


監(jiān)聽Home Screen Quick Actions選項(xiàng)的選擇并進(jìn)行處理

監(jiān)聽Home Screen Quick Actions選項(xiàng)的點(diǎn)擊選擇,我們要在AppDelegate中實(shí)現(xiàn)方法application(_:, performActionForShortcutItem:, completionHandler:),判斷用戶選擇的是哪一個(gè)選項(xiàng),然后進(jìn)行相應(yīng)的操作:

    func application(application: UIApplication, performActionForShortcutItem shortcutItem: UIApplicationShortcutItem, completionHandler: (Bool) -> Void) {
        switch shortcutItem.type {
        case ShortcutItemType.Home.rawValue:
            print("選擇了主頁選項(xiàng)")
        case ShortcutItemType.Share.rawValue:
            print("選擇了分享選項(xiàng)")
        default:
            print("選擇了其他選項(xiàng)")
        }
        completionHandler(true)
    }

在方法的最后記得調(diào)用completionHandler閉包,把是否處理完成的布爾值傳進(jìn)去,如成功處理完,傳true,失敗,則傳false


注意:關(guān)于方法application(_:, performActionForShortcutItem:, completionHandler:),蘋果官方文檔給出了使用的相關(guān)注意事項(xiàng):

這個(gè)方法會(huì)在你選擇了某個(gè)Home Screen Quick Actions選項(xiàng)時(shí)調(diào)用,但是前提條件是AppDelegate中的application(_:,willFinishLaunchingWithOptions:)方法以及application(_:didFinishLaunchingWithOptions)方法都要返回true真值。蘋果建議這個(gè)方法是在應(yīng)用已經(jīng)啟動(dòng)了、在后臺(tái)工作的時(shí)候才去監(jiān)聽Home Screen Quick Actions選項(xiàng)的選擇,若我們在應(yīng)用程序還未啟動(dòng)的時(shí)候使用Home Screen Quick Actions選擇某個(gè)選項(xiàng),我們就不應(yīng)該使用這個(gè)方法來進(jìn)行監(jiān)聽,應(yīng)當(dāng)在application(_:,willFinishLaunchingWithOptions:)方法或者application(_:didFinishLaunchingWithOptions)方法里進(jìn)行操作,最后返回false,使得AppDelegate不會(huì)再去調(diào)用application(_:, performActionForShortcutItem:, completionHandler:)這個(gè)方法。


那么,當(dāng)Home Screen Quick Actions選項(xiàng)在應(yīng)用還未啟動(dòng)時(shí)被選擇了,我們應(yīng)該如何在AppDelegate中的application(_:,willFinishLaunchingWithOptions:)方法或application(_:didFinishLaunchingWithOptions)方法里監(jiān)聽Home Screen Quick Actions選項(xiàng)的選擇以及做出相應(yīng)的操作呢?這里我們可以從這兩個(gè)方法的launchOptions參數(shù)中獲取到對應(yīng)的shortcutItem

let shortcutItem = launchOptions?[UIApplicationLaunchOptionsShortcutItemKey] as? UIApplicationShortcutItem

下面我就重寫application(_:didFinishLaunchingWithOptions)來演示一下:

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    
        //  TODO: 應(yīng)用的初始化代碼,包括UIWindow以及UIViewController等等的配置...
        
        var performActionForShortcutItemWhenAppLaunch = false
        //  判斷應(yīng)用的啟動(dòng)是否是因?yàn)橛脩暨x擇了Home Screen Quick Actions選項(xiàng)
        if let shortcutItem = launchOptions?[UIApplicationLaunchOptionsShortcutItemKey] as? UIApplicationShortcutItem {
            performActionForShortcutItemWhenAppLaunch = true
            print("選擇了\(shortcutItem.type)類的選項(xiàng)")
            //  TODO: 相應(yīng)的Handle操作
        }
        
        return !performActionForShortcutItemWhenAppLaunch
    }

如上方代碼所示,我在前面就定義了以布爾型變量performActionForShortcutItemWhenAppLaunch,默認(rèn)值為false,然后再從launchOptions中取出shortcutItem,如果shortcutItem為空,則說明應(yīng)用的啟用是由于用戶點(diǎn)擊了應(yīng)用的圖標(biāo),而不是通過Home Screen Quick Actions;如果shortcutItem不為空,則說明用戶是用過點(diǎn)擊shortcutItem對應(yīng)的選項(xiàng)來啟動(dòng)應(yīng)用的,這時(shí)候我將true值賦值給了performActionForShortcutItemWhenAppLaunch。在方法的最后,我通過返回performActionForShortcutItemWhenAppLaunch的布爾相反值,來讓應(yīng)用避免調(diào)用application(_:, performActionForShortcutItem:, completionHandler:)方法。

Peek And Pop

Peek And PopHome Screen Quick Actions來說更為復(fù)雜,下面我就PeekPeek quick actionsPop的實(shí)現(xiàn)進(jìn)行分析。

Peek & Pop

實(shí)現(xiàn)PeekPop首先我們要關(guān)注協(xié)議UIViewControllerPreviewingDelegate,它有兩個(gè)需要我們?nèi)?shí)現(xiàn)的方法:

  • previewingContext(_:, viewControllerForLocation:) -> UIViewController

    Peek就是用戶用力按壓屏幕某個(gè)地方時(shí),周圍變得模糊,然后隨著按壓的力度加強(qiáng),最后會(huì)有一個(gè)預(yù)覽視圖彈出。舉個(gè)例子,屏幕上有一個(gè)TableView,當(dāng)我們手指按壓其中某個(gè)Cell時(shí),Cell的周圍就會(huì)變得模糊,然后關(guān)于這個(gè)Cell的預(yù)覽視圖就出現(xiàn)了。這個(gè)方法就是用于配置此過程中的相關(guān)邏輯,并返回最終的預(yù)覽視圖所屬的視圖控制器。在這個(gè)方法中,我們需要配置一些東西:

    1. previewingContext參數(shù)中的sourceRect。這是一個(gè)CGSize類型,我們要將手指所按壓的視圖控件的frame賦值給它,從而讓系統(tǒng)精確將視圖控件的周圍模糊掉;如何獲取被按壓的視圖控件呢?方法的viewControllerForLocation參數(shù)就是當(dāng)用戶用力按壓時(shí)手指的按壓點(diǎn),我們可以利用這個(gè)按壓點(diǎn)來找到包含此點(diǎn)的視圖控件。
    2. 詳情視圖控制器的創(chuàng)建、預(yù)覽尺寸設(shè)置以及返回。在這個(gè)方法里,我們得實(shí)例化我們要預(yù)覽時(shí)展現(xiàn)出來的詳情視圖控制器,并且利用preferredContentSize設(shè)置它的預(yù)覽大小,這是一個(gè)CGSize類型,當(dāng)我們把長寬都設(shè)置為0.0的時(shí)候,預(yù)覽視圖大小就會(huì)采用系統(tǒng)默認(rèn)的尺寸值。
  • previewingContext(_:, commitViewController:)

    Pop操作就是在這個(gè)方法里執(zhí)行,在前面已經(jīng)說到,Pop其實(shí)就是我們傳統(tǒng)情況下點(diǎn)擊控件然后應(yīng)用跳出詳情視圖控制器這一過程,所以,在這里我們需要做的就是把詳情視圖控制器展現(xiàn)出來。方法中的commitViewController參數(shù)就是我們在前面方法中返回的詳情視圖控制器,我們在這個(gè)方法中將其"Show"出來即可。

下面就是參考的代碼:

//  MARK: - UIViewControllerPreviewingDelegate
extension ViewController: UIViewControllerPreviewingDelegate {
    func previewingContext(previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
        guard let indexPath = self.tableView.indexPathForRowAtPoint(location) else { return nil }
        let selectedCellFrame = tableView.cellForRowAtIndexPath(indexPath)!.frame
        
        let detailViewController = DetailViewController()
        detailViewController.mainTitle = self.tableViewData[indexPath.row]
        detailViewController.preferredContentSize = CGSize(width: 0.0, height: 350)
        
        previewingContext.sourceRect = selectedCellFrame
        
        return detailViewController
    }
    
    func previewingContext(previewingContext: UIViewControllerPreviewing, commitViewController viewControllerToCommit: UIViewController) {
        self.showViewController(viewControllerToCommit, sender: self)
    }
}

當(dāng)我們實(shí)現(xiàn)了UIViewControllerPreviewingDelegate協(xié)議后,我們就可以為視圖控制器注冊Peek預(yù)覽了,不過,在注冊的時(shí)候一定要先判斷好設(shè)備的3D Touch是否可用:

//  MARK: - Setup 3D Touch
        if self.traitCollection.forceTouchCapability == .Available {
            self.registerForPreviewingWithDelegate(self, sourceView: self.tableView)
        } else {
            print("3D Touch 不可用!")
        }

這里我們使用UIViewController中的方法registerForPreviewingWithDelegate(_:, sourceView:)來進(jìn)行Peek注冊,方法第一個(gè)傳入的參數(shù)就是實(shí)現(xiàn)了UIViewControllerPreviewingDelegate的實(shí)例,第二個(gè)參數(shù)就是手指按壓的監(jiān)聽視圖。

Peek quick actions

Peek的快速操作是在詳情視圖控制器中實(shí)現(xiàn)的,我們只需重寫這個(gè)視圖控制器的previewActionItems() -> [UIPreviewActionItem]方法,返回一個(gè)數(shù)組即可。
UIPreviewActionItem為一個(gè)協(xié)議,一般我們需要?jiǎng)?chuàng)建的是UIPreviewAction或者UIPreviewActionGroup實(shí)例。

  • UIPreviewAction就是代表一個(gè)選項(xiàng),它的構(gòu)造方法為init(title: String, style: UIPreviewActionStyle, handler: (UIPreviewAction, UIViewController) -> Void),設(shè)置的是選項(xiàng)的標(biāo)題、類型以及選項(xiàng)選擇后所需要處理的操作。這里的類型UIPreviewActionStyle有三種,分別是默認(rèn)類型、已選擇類型(旁邊有一個(gè)勾)、取消類型(標(biāo)題顏色為紅色)。
  • UIPreviewActionGroup是一個(gè)UIPreviewAction的分組,它的構(gòu)造方法為init(title: String, style: UIPreviewActionStyle, actions: [UIPreviewAction]),傳入的參數(shù)為標(biāo)題以及組成這個(gè)小組的UIPreviewAction成員數(shù)組。它的作用是當(dāng)我們點(diǎn)擊這個(gè)小組選項(xiàng)時(shí),它就會(huì)將自己的成員選項(xiàng)們展開并呈現(xiàn)出來。

這里提供參考代碼:

    private lazy var previewActions: [UIPreviewActionItem] = {
        let action1 = UIPreviewAction(title: "分享", style: .Default, handler: { action, viewController in
            print("Peek quick actions- 分享")
        })
        let action2 = UIPreviewAction(title: "搜索", style: .Default, handler: { action, viewController in
            print("Peek quick actions- 搜索")
        })
        let action3 = UIPreviewActionGroup(title: "更多", style: .Default, actions: [action1, action2])
        return [action1, action2, action3]
    }()

//  MARK: - Setup PreviewActionItems
    override func previewActionItems() -> [UIPreviewActionItem] {
        return self.previewActions
    }

應(yīng)用運(yùn)行的效果圖如下:


3D Touch的其他API

蘋果為3D Touch提供了Force Properties(按壓強(qiáng)度屬性),我們可以在UITouch類中找到屬性forcemaximumPossibleForce,分別代表瞬時(shí)按壓力度以及設(shè)備最大可能達(dá)到的按壓力度,我們可以利用這兩個(gè)屬性完成很多有趣的交互,這就要看大家的想象力了,在這里我就舉一個(gè)簡單的小例子:

我編寫了一個(gè)UIView的子類,它的大小由我們手指按壓它的力度去決定,這是它的內(nèi)部代碼:

class ResizeableView: UIView {
    override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
        var multiple: CGFloat = 0.0
        if let force = touches.first?.force, let maximumPossibleForce = touches.first?.maximumPossibleForce {
            multiple = force / maximumPossibleForce
        }
        self.transform = CGAffineTransformMakeScale(1 + multiple, 1 + multiple)
    }
}

現(xiàn)在我在一個(gè)視圖控制器中創(chuàng)建它的一個(gè)實(shí)例,并添加到控制器的視圖中,然后隨便設(shè)置一個(gè)frame給它:

class TouchViewController: UIViewController {
    
    private let mViewSizeValue: CGFloat = 70.0
    
    private lazy var mView: ResizeableView = {
        let view = ResizeableView()
        view.backgroundColor = UIColor.redColor()
        return view
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.addSubview(self.mView)
        self.mView.frame = CGRectMake(100, 200, mViewSizeValue, mViewSizeValue)
    }

}

于是乎,一個(gè)利用簡單的利用forcemaximumPossibleForce屬性的小例子就做出來了。我們運(yùn)行一下看看效果:

總結(jié)

這篇文章向大家介紹了3D Touch的特性,并詳細(xì)講解了有關(guān)于3D Touch開發(fā)API的使用。相關(guān)代碼我已經(jīng)發(fā)布到個(gè)人的GitHub上:Tan3DTouch
感謝大家的閱讀,在這里也祝大家夏日愉快!

參考資料

蘋果官方文檔:
Adopting 3D Touch on iPhone
iOS Human Interface Guidelines: 3D Touch

蘋果官方參考項(xiàng)目:
ApplicationShortcuts: Using UIApplicationShortcutItem
ViewControllerPreviews: Using the UIViewController previewing APIs

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,401評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,011評論 3 413
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,263評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,543評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,323評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,874評論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,968評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,095評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,605評論 1 331
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,551評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,720評論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,242評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 43,961評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,358評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,612評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,330評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,690評論 2 370

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

  • 前言 關(guān)于3D touch蘋果官方文檔是這么開始介紹的: 大意如下:iOS9開始,所有新的手機(jī)都增加了一個(gè)三維的用...
    VV木公子閱讀 2,241評論 3 39
  • 3D Touch 給iOS9的用戶一個(gè)維度的交互。在支持的設(shè)備上,人們能夠在主屏幕界面通過按壓應(yīng)用程序圖標(biāo),快速的...
    Jack__yang閱讀 602評論 0 2
  • 專著:http://www.lxweimin.com/p/3443a3b27b2d 1.簡單的介紹一下3D Touc...
    violafa閱讀 1,021評論 1 0
  • 1.簡單的介紹一下3D Touch 3D Touch的觸控技術(shù),被蘋果稱為新一代多點(diǎn)觸控技術(shù)。其實(shí),就是此前在Ap...
    Camille_chen閱讀 12,069評論 19 33
  • 3D Touch簡介 2015年,蘋果發(fā)布了iOS9以及iphone6s/iphone6s Plus,其中最具有創(chuàng)...
    愛恨的潮汐閱讀 386評論 0 2