閱讀397 返回首頁    go 王者榮耀


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

蘋果公司通過 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觸控的看法。

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

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

最後更新:2017-04-01 13:44:32

  上一篇:go PostgreSQL 路徑規劃插件 pgruoting 介紹
  下一篇:go 深入淺出JProfiler