可能你们看了标题,都没明白: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 的总内存却不断上涨。须要你们在开发中注意,暂无好的解决办法。