可能你們看了標題,都沒明白:AR 中的二維手勢是個什麼玩意?swift
其實就是給 AR 物體貼圖,在貼圖中放一個 UIButton 或 UIScrollView,又或者自定義 View, 看它們能不能正常響應手勢,以及能響應哪些手勢。app
關於貼圖能夠看 SCNNode到底應該怎麼貼圖?UIImage,UIImageView,CALayer用哪一個?ide
須要注意的是:蘋果官方目前(至 iOS13)都並不推薦貼圖使用 UIView 類,可能會有潛在的佈局問題,內存問題等。蘋果論壇上官方員工的回覆forums.developer.apple.com/message/340… 佈局
通過測試發現,平時咱們使用各類手勢,在 AR 中基本都是可使用的。包括:UIButton 的各類手勢,UIScrollView 拖拽手勢,UITapGestureRecognizer 手勢, 甚至是 UICollectionView 的選中 cell 手勢均可以正常工做。post
以下圖:淺灰色背景是 UIView;左上角放置兩個 UIButton,黑色和深灰色;右下角大塊的是 UICollectionView,三個 cell 顏色不一樣。測試
須要注意的是:當給整個 View 添加了 UITapGestureRecognizer 手勢後, UICollectionView 的選中 cell 手勢就再也不響應了。以下圖:spa
在開發中遇到常見問題,一個是 AR手勢與屏幕手勢優先級問題,這個下面再講。另外一個是 AR 中 UIButton
的touchUpInside
手勢,有時難以觸發的問題。code
尤爲是在距離 AR 平面比較遠(2 米外),沒有正面對着平面時(斜着點擊),很是嚴重。常常能夠看到按鈕已經被按下並處於高亮狀態了,可是閃一下後又退出了高亮狀態,而手勢並無被觸發。cdn
我想多是由於touchUpInside
要求手指按下時和離開時,都要在按鈕內部,這樣纔會觸發。而 AR 中的按鈕要想被點擊,須要一隻手拿着手機,另外一隻手點擊屏幕中 AR 平面的區域,這樣形成的點擊時抖動太大。blog
這樣在 AR 中的按鈕看來:手指按下了按鈕(touchDown),而後抖動嚴重,跑到了按鈕外面(outside),這樣是不符合 touchUpInside 定義的,因此不會觸發。
爲了按鈕手勢更好的觸發,將按鈕觸發條件改成touchDown
,能夠有效提升 AR 按鈕點擊響應的機率。
還有一個相似的問題,是 AR 中 UIScrollView 的拖拽手勢在拖動時常常會中斷和抖動,尤爲是從側面進行拖拽時。好在這個問題不太嚴重,也沒有什麼太好的處理方法。
本來在 iOS 12 中只有 UIButton 的touchUpInside
手勢會出現難以響應的問題,更新 iOS 13 後,UICollectionView 選中 cell 手勢(didSelectItemAt)也出現了幾乎如出一轍的選中困難問題,嚴重時點擊 10 次都會觸發一次。
爲了緩解這個問題,不得不給整個 UICollectionView 添加了 UITapGestureRecognizer 手勢,來代替 didSelectItemAt 事件。
通過測試,發現優先級:AR 貼圖手勢 > 屏幕手勢,哪怕你的 ARSCNView 在下面,而屏幕手勢被添加的 UIView 層級更高,也仍然是 AR 中的手勢先觸發。
具體來講:AR 中 UIButton 手勢(touchUpInside/touchDown) > AR 中 UIScrollView 拖拽手勢 > AR 中的 UITapGestureRecognizer 手勢 > AR 中的 UICollectionView 選中 cell 手勢(didSelectItemAt) > 屏幕上的 UIButton 手勢 > 屏幕中的 UITapGestureRecognizer 手勢....
下面,咱們給屏幕中添加一個 UIButton,而後測試點擊它,注意觀察當它後面有 AR 內容時,和沒有 AR 內容時,響應是不同的。只有當 screenButton 後面的 AR 物體不能響應時,screenButton 的手勢才能觸發(arButton2 在錄製時沒點擊到)
若是把屏幕上的 UIButton 換成對整個 View 添加 UITapGestureRecognizer 手勢,結果也是同樣的
即便你在控制器界面實現touchesBegan
方法也是同樣,低優先級被觸發:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
}
複製代碼
實踐一番下來,蘋果的各類手勢基本都能在 AR 貼圖中使用,即便個別有問題也可能經過變通的方式來解決。
真正麻煩的是 AR 貼圖手勢與屏幕手勢之間的優先級問題。一旦貼圖中有了手勢,它就會永遠處於第一級響應者,致使咱們在屏幕上的 UI 控件沒法響應。這無疑給咱們開發時增長了困難。
爲了兼容兩種手勢事件,不得不在屏幕上有控件須要點擊時,臨時禁用 AR 貼圖中的手勢。屏幕控件消失後,再啓用貼圖中的手勢
可是若是屏幕上確實有控件須要一直顯示並等待點擊,而 AR 貼圖中也須要一直顯示並等待點擊,該怎麼辦呢?好比在 AR 貼圖中有個按鈕,屏幕上也有個按鈕,當用戶把兩個按鈕重合時,點擊一下,響應確定的是 AR 中的按鈕,這卻並非咱們想要的結果。
暫時想到的方法是,用下面的方法來把 AR 中按鈕的 3D 位置,投影到屏幕上,看看屏幕上對應位置有沒有須要響應的按鈕
func projectPoint(_ point: SCNVector3) -> SCNVector3
複製代碼
可是這樣也會有不少複雜步驟:
全部這些都嚴重增長了開發的複雜度,形成得不償失。因此仍是建議少在 AR 貼圖中使用手勢,若是必需要使用就注意減小與屏幕控件的手勢衝突。
另外,使用 UIView 做爲 SCNNode 的貼圖,疑似存在內存泄露的問題:View 和 Node 都銷燬了,但 app 的總內存卻不斷上漲。須要你們在開發中注意,暫無好的解決辦法。