3D觸控簡介:建立數字刻度應用及快速活動欄

OneAPM官方技術部落格發表於2015-12-23

蘋果公司通過 iPhone 6s 和 6s Plus 引入了與手機互動的全新方式:按壓手勢。你也許知道,蘋果智慧手錶和蘋果膝上型電腦早已具備這一功能,只是名稱略有不同,為力感觸控(Force Touch)。無不誇張地說,這一功能給使用者介面增加了全新的維度。

iOS

如果你在想,為什麼將力感觸控在 iPhone 中改名為 3D 觸控,那你真的不是一個人。克雷格·費德里吉對這一命名也十分困惑,在他提出這一新功能後不久,便在推特引起了反響:力感觸控的名稱怎麼了?開什麼國際玩笑?

但兩者還是存在明顯差異的!力感觸控只能檢測到用力按壓,而 3D 觸控顯然更加敏感。它能夠根據你的按壓力度,將觸控分為不同的等級。

雖然這一變化看起來並不重要,但它讓開發商得以對手機進行更加精確的測量。舉個例子,重力這一應用可以用力感觸控將你的 iPhone 轉換為數字刻度。雖然蘋果公司以不明原因拒絕了這一應用,這個概念依然十分出彩。因此,為了更好地展示 3D 觸控的執行方式,讓我們一起來做一個類似的應用吧!

精彩由此開始

首先,點此下載我製作的專案模板。基本上這只是一個空的單一檢視 iPhone 應用,我建立了應用設計(UILables和UIImage)並與 ViewController.swift 中的 IBOutlets 進行連線。

這一應用的設計很簡單:一個帶有兩個標籤的檢視控制器,一個標籤為標題而另一個標籤會在 iPhone 上顯示力度百分比。

那麼,現在開始編碼。在 iPhone 6s 和 6s Plus 上,UITouch 物件有兩個新的 CGFloat 屬性,分別是 force(力度)和 maximumPossibleForce (最大可能力度)。force 表示觸控的力度,1.0 表示平均觸控力度,MaximumPossibleForce 表示最大的觸控力度。

任何時候,使用者觸及螢幕上的內容都會導致依次呼叫「touchesBegan(開始觸控)」和「touchesMoved(移動觸控)」方法。如果使用者在螢幕上挪開手指,根據情境的不同會呼叫「touchedCancelled(取消觸控)」或「TouchesEnded(結束觸控)”方法。為了達到本應用的目的,我們僅需要 touchesMoved 方法。touchesMoved 有兩個引數:touches (觸控)和 events(事件)。touches 是一組 UITouch 物件的集合(無序的不同物件集合)。在 touches 中必須有且僅有一個 UITouch 物件,但我們越仔細越好,所以強烈建議通過可選繫結檢查確定「touches.first」(touches 集合的第一個 UITouch 物件)是否為空。在「ViewController.swift」 中插入以下方法:

override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
    if let touch = touches.first {
        if #available(iOS 9.0, *) {
            if traitCollection.forceTouchCapability == UIForceTouchCapability.Available {
                // 3D Touch capable
            }
        }
    }
}

在 if 從句中,驗證裝置是否支援 3D 觸控。如果你製作此專案僅是為了娛樂,那麼這步操作是可選的。但是,如果你想把該應用放到應用商店中,則必須進行檢查,因為 iPhone 6 之類較舊的裝置並不支援 3D 觸控。

注意,還需檢查裝置能否執行 iOS 9.0 或以上版本的系統。我通過 Swift 2.0中引進的新 #available 句法進行檢查。如果你想了解更多關於 Swift 2.0 的資訊,我推薦你閱讀此文。再次申明,如果你的部署目標為 9.0 或以上系統,則這一檢查項為可選項。

計算力度百分比時,只需將觸控力度除以最大力度(即 touch.maximumPossibleForce)即可,最大力度為一次觸控可能的最大力度。隨後,更新該標籤的文字內容。你可以像下面這樣更新此方法:

override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
    if let touch = touches.first {
        if #available(iOS 9.0, *) {
            if traitCollection.forceTouchCapability == UIForceTouchCapability.Available {
                // 3D Touch capable
                let force = touch.force/touch.maximumPossibleForce
                forceLabel.text = "\(force)% force"
            }
        }
    }
}

如果在 iPhone 6s 或 6s Plus 上執行該應用,按壓螢幕時應該會顯示力度百分比。但因為我們是在製作刻度 App,你可能還想新增在 iPhone 上所施加重量的克數。根據瑞恩•麥克勞德的實驗,感測器能承受的最大重量為358g。因此,對應的最大可能力度為 385 克(約 3.8 牛)。通過簡單的計算,將力度百分比乘以 385,你就可以將其轉換為克數。對於重量不小於 385 克的物體,我們只需更改標籤,註上「385克+」 之類的內容即可。

現在,請用下面的程式碼片段更新方法:

override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {        
    if let touch = touches.first {
        if #available(iOS 9.0, *) {
            if traitCollection.forceTouchCapability == UIForceTouchCapability.Available {
                if touch.force >= touch.maximumPossibleForce {
                    forceLabel.text = "385+ grams"
                } else {
                    let force = touch.force/touch.maximumPossibleForce
                    let grams = force * 385
                    let roundGrams = Int(grams)
                    forceLabel.text = "\(roundGrams) grams"
                }
            }
        }
    }
}

太酷了!你已經完成了數字刻度應用的製作。

現在,物體或手指離開螢幕後,應用並不會將重量重置為零。你可以通過「touchesEnded(結束觸控)」方法重置標籤。

override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
    forceLabel.text = "0 gram"
}

主螢幕快速操作

3D 觸控的另一個主要功能是主螢幕中的快速操作。快速操作給使用者提供了直接跳到應用某個部分的快捷方式。只要用力按壓應用圖示,就能看到其快捷方式。3D 觸控引進之後,推特、Instagram 及其他蘋果應用都開始使用這一新功能。

現在,我們來給刻度應用新增一個快速操作:在藍色背景(而不是白色背景)下開啟應用。首先,開啟專案中的 info.plist(點選專案導航器中的刻度工作區(Scale workspace),選擇刻度目標(Scale target),然後進入資訊標籤(Info tab))檔案。在檔案中新增「UIApplicationShortcutItems(使用者介面應用快捷方式專案)」陣列。陣列中的每個元素都是包含一個快速操作屬性的詞典。

  • UIApplicationShortcutItemType(使用者介面應用快捷方式專案型別)(必選):該字串可識別快速操作。注意,該字串必須是此應用特定的唯一字串。你可以用資源包 ID 或其它應用唯一的字串為該字串新增字首。
  • UIApplicationShortcutItemTitle(使用者介面應用快捷方式專案標題)(必選):該字串代表該快速操作的標題,會展示給使用者。例如「顯示最近拍攝的照片」。
  • UIApplicationShortcutItemSubtitle(使用者介面應用快捷方式專案子標題)(可選):該字串位於快速操作的標題下方,例如「昨天拍攝的最後一張照片」。你可以通過以下兩種方法為快速操作新增圖示:蘋果自帶的系統圖示,或你自定義的圖示。
  • UIApplicationShortcutItemIconType(使用者介面應用快捷方式專案圖示型別)(可選):該字串代表你想在快速操作旁顯示的系統圖示。
  • UIApplicationShortcutItemIconFile(使用者介面應用快捷方式專案圖示檔案)(可選):該字串代表你想在快速操作旁邊顯示的自定義圖示。
  • UIApplicationShortcutItemUserInfo(使用者介面應用快捷方式專案使用者資訊)(可選):該字典包含你希望與快速操作一起傳遞的額外資訊。

在陣列中,我們定義四個專案配置“開啟藍色”快速操作。你的 info.plist 應如下所示:

請注意,我用的是「$(PRODUCT_BUNDLE_IDENTIFIER)」而不是「com.appcoda.Scale」或你所使用的其他資源包 ID。此做法是出於安全考慮。如果你因為某種原因更改了「General(總覽)」中的資源包 ID,整個專案將受到影響,而且所有的資源包 ID 都將改變。否則,我不得不手動更改各處的 ID。在「info.plist」檔案中,你可以看到包識別符號金鑰(Bundle Identifier key)使用同樣的途徑「$(PRODUCT_BUNDLE_IDENTIFIER)」來描述到你的專案資源包 ID 的路徑

最後還有一件事要做:在使用者實際觸發該快速操作時執行之。快捷方式通常由AppDelegate.swift 中的 performActionForShortcutItem 方法處理。當快速操作被啟用時,該方法將會被呼叫。因此你必須實現該方法以處理快速操作: ``` func application(application: UIApplication, performActionForShortcutItem shortcutItem: UIApplicationShortcutItem, completionHandler: (Bool) -> Void) {

// Handle quick actions
completionHandler(handleQuickAction(shortcutItem))

} ```

你還應呼叫完成處理程式(completion handler),並傳入代表快速操作成敗的布林值。此處,我們建立一個名為「handleQuickAction (處理快速活動欄)」的獨立方法來處理快捷方式。一個表述多個快速操作案例的好辦法是:使用列舉,並以 「UIApplicationShortcutItemType(使用者介面應用快捷方式專案型別)」為原始值。宣告一個列舉物件,按照下例實現 「handleQuickAction(處理快速活動欄)」方法,在應用通過該快速操作啟動時將背景顏色設定成藍色。 ``` enum Shortcut: String { case openBlue = "OpenBlue" }

func handleQuickAction(shortcutItem: UIApplicationShortcutItem) -> Bool {

var quickActionHandled = false
let type = shortcutItem.type.componentsSeparatedByString(".").last!
if let shortcutType = Shortcut.init(rawValue: type) {
    switch shortcutType {
    case .openBlue:
        self.window?.backgroundColor = UIColor(red: 151.0/255.0, green: 187.0/255.0, blue: 255.0/255.0, alpha: 1.0)
        quickActionHandled = true
    }
}

return quickActionHandled

} ```

非常簡單。如果你現在執行應用,並通過該快速操作啟動應用,背景就會變成藍色。

注意事項

還有一件事需要牢記,依據啟動次序的不同,正在啟動的應用與通過快速操作恢復的應用之間存在差別。如你所知,應用啟動時會呼叫willFinishLaunchingWithOptions 與 didFinishLaunchingWithOptions 方法。但通過快速操作恢復應用時,只會觸發「theperformActionForShortcutItem (執行快捷方式專案活動)」方法。

如果你在檢視「didFinishLaunchingWithOptions(已通過選項完成啟動)」方法的實現細節,會發現一行程式碼將背景顏色設定為白色。該方法在應用通過圖示點選正常啟動時使用。 ``` func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { // Override point for customization after application launch. self.window?.backgroundColor = UIColor.whiteColor()

return true

} ```

這正是問題所在:通過快速操作啟動應用時,「willFinish」、「didFinish」和「performActionForShortcutItem(執行快捷方式專案活動)」將被依次呼叫。因此背景會先變成白色,再變成藍色。顯然,當使用者通過快速操作啟動應用時,你並不希望將背景顏色設定成白色。

要解決這個問題,我們不得不為「didFinishLaunchingWithOptions(已通過選項完成啟動)」方法實施條件檢查。 ``` func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { print("didFinishLaunchingWithOptions called") var isLaunchedFromQuickAction = false

// Check if it's launched from Quick Action
if let shortcutItem = launchOptions?[UIApplicationLaunchOptionsShortcutItemKey] as? UIApplicationShortcutItem {

    isLaunchedFromQuickAction = true
    // Handle the sortcutItem
    handleQuickAction(shortcutItem)
} else {
    self.window?.backgroundColor = UIColor.whiteColor()
}

// Return false if the app was launched from a shortcut, so performAction... will not be called.
return !isLaunchedFromQuickAction

} ```

為了確定應用是否通過快速操作啟動,你可以檢查「UIApplicationLaunchOptionsShortcutItemKey(使用者介面應用啟動選項快捷方式專案金鑰)」啟動選項鍵。「UIApplicationShortcutItem(使用者介面應用快捷方式專案)」物件可提供啟動選項鍵的值。若應用通過快速操作啟動,我們可以呼叫「handleQuickAction(處理快速活動欄)」方法將背景改為藍色。

因為已經通過「didFinishLaunchingWithOptions(已通過選項完成啟動)」處理過該快速操作,我們不想呼叫「performActionForShortcutItem(執行快捷方式專案活動)」再次執行「handleQuickAction(處理快速活動欄)」方法。所以,我們最終返回一個false值,告訴系統不必呼叫「performActionForShortcutItem(執行快捷方式專案活動)」方法。

就是這樣!現在你可以重新測試應用了,快速操作將完美執行。

總結

3D 觸控是給應用增加方便、有趣的附屬特性的好辦法。但你必須清楚,並不是所有的裝置都支援 3D 觸控,雖然未來這一情況可能改變。

閱讀此文後,你應該能夠給你的 iOS 應用新增快速操作,並確定觸控力度。

你可以點選此處下載完整的 Xcode專案程式碼,以供參考。跟以前一樣,請留下你的評論,並分享對教程和3D觸控的看法。

原文地址:http://www.appcoda.com/3d-touch-tutorial/

OneAPM Mobile Insight 以真實使用者體驗為度量標準進行 Crash 分析,監控網路請求及網路錯誤,提升使用者留存。訪問 OneAPM 官方網站感受更多應用效能優化體驗,想閱讀更多技術文章,請訪問 OneAPM 官方技術部落格

相關文章