NeedHelp101
NeedHelp101

Reputation: 639

Remove touch gestures (rotation/translation) for Ios ar object

Summary: Remove touch gestures on an AR object after adding it?

AR View Code (Just the relevant bit). Where arObject is a model entity with a mesh, material and a collision shape.

func updateUIView(_ uiView: ARView, context: Context) {
  arObject = CreateCustomModelEntity()
  uiView.installGestures([.translation, .rotation], for: arObject)
}

The above could would add touch gestures to my arObject and allow it to be rotated and moved across the anchored plane.

However, I want to remove the touch gestures after adding it.

User Flow:

The user would click a model, move it around and place it where they'll like and touch the Confirm button. After the confirm button is touched, the arObject can no longer be moved around.

Looking at the Apple docs, there's an installGestures, but no equivalent removeGestures. Is this even possible?

A few ideas,

  1. completely remove the anchor and recreate it (but then the placement of the object is lost, so this is bad)
  2. Override the existing child ar object with a new one without the touch gestures installed. I believe this would retain the object placement, but double creating ar objects isn't ideal unless there's no other solution.
  3. Create a temp ar object with install gestures and then override it with a new arObject (without touch gestures) after placement has been confirmed. Similar to 2. solution.

Upvotes: 3

Views: 770

Answers (2)

Darkwonder
Darkwonder

Reputation: 1305

Tested on Xcode 14.0, and Swift 5.7. :

import Foundation
import RealityKit


public extension ARView {
    
    func removeAllGestureRecognizers() {
        if Thread.isMainThread {
            self.gestureRecognizers?.forEach({ self.removeGestureRecognizer($0)})
        } else {
            DispatchQueue.main.async { [weak self] in self?.removeAllGestureRecognizers() }
        }
    }
    
    func removeEntityGestureRecognizer(_ entityGestureRecognizer: EntityGestureRecognizer?) {
        
        guard let eEntityGestureRecognizer = entityGestureRecognizer else { return }
        guard let gestureRecognizers = self.gestureRecognizers else { return }
        
        if Thread.isMainThread {
            guard let egrIndex = gestureRecognizers.firstIndex(of: eEntityGestureRecognizer) else { return }
            self.gestureRecognizers?.remove(at: egrIndex)
        } else {
            DispatchQueue.main.async { [weak self] in self?.removeEntityGestureRecognizer(eEntityGestureRecognizer) }
        }
   
    }
    
}

Upvotes: 0

iPavleas
iPavleas

Reputation: 67

The installGestures method returns an array of EntityGestureRecognizers and also assigns these gesturesRecognizers to the arView.gesturesRecognizers array. If you want to remove gestures for a given entity you need to find the gesturesRecognizers you want and remove them from that array.

The code below assigns the translation and rotation gestureRecognizers separately to a property which you use to find the corresponding index in the arView.gesturesRecognizers array.

func updateUIView(_ uiView: ARView, context: Context) {
    arObject = CreateCustomModelEntity()
    translationGestureRecognizer = uiView.installGestures([.translation], for: arObject).first
    rotationGestureRecognizer = uiView.installGestures([.rotation], for: arObject).first
}

func removeGesture() {
    let recognizerIndex = arView.gestureRecognizers?.firstIndex(of: translationGestureRecognizer!)
    arView.gestureRecognizers?.remove(at: recognizerIndex!)
}

    

I found removing gestureRecognizers from the arView mandatory also when removing an object from the scene because otherwise it isn't released from memory and thus it increases the app's footprint.

Upvotes: 6

Related Questions