Send double tap to SCNView - ios

SCNView build camera control has a function,double tap sceneview and roll back camera to start position when allowsCameraControl is enabled.
i went to add a button do the same thing
when user click the button i will roll back camera to start position
there is no class implement UIControl in scenekit
so i can't use sendAction
i can set camera position by scnView.pointOfView
but there is a animation when user scroll the camera, set camera position will fail when animation is running.
is there a good way to reset the camera ??

NicoS's answer effectively handles the part of your question about making a user action change the camera POV.
As for your issue with undesired animation when setting pointOfView — you can control that animation (and any other implicit animations that happen when you change object properties) using the SCNTransaction class. To make a change with no animation, just do this (Swift 3):
SCNTransaction.begin()
SCNTransaction.animationDuration = 0
// perform your changes...
view.pointOfView = newCameraNode
// ...and anything else you want to happen in the same non-animated update, then...
SCNTransaction.commit()

Just add a TapGestureRecognizer to your Storyboard, to the view that has the SCNView. Connect the gesture recognizer action to your class so that you have an IBAction. Set the number of taps to two taps in the Storyboard Attributes Inspector. Now you can add your code to reset the camera.

Related

Pin Button on 3d Object in ARkit

I am trying to Pin button on a 3d object. When the TouchBegan function loads, I use touch to place object in the world. I want the buttons to be pinned on the object when i load the object.
I am unable to find AR Button in arkit. All i can found is to place text as child node and name the node and get the first hit result and get the child node by name to triggers buttons.
The Button placing to object with relative to 3d space is an issue. Looking for possible solutions.
This is what i wanted to achieve and currently am using the github project as a demo.
https://github.com/eh3rrera/ARKitSceneKitExample
I suggest using box/plane with SKScene as material for button and text in SKScene as title. Then you can use hitTest in tapGesture. And maybe animate color change to have button pressed effect.
The way I solved the button problem in ARKit wast to create a physical button as part of the 3D model
you don’t need to create buttons with text, for say tapping open the door or switching a light... but you need to somehow communicate to the user they can tap (the door to open or tap a light to switch on).
To active the node you give it a unique node.name “front_door”
node.name = “front_door”
One downside is you have to do naming of nodes using xcode before the program is executed.
Below is the swift code for responding to the tap on the button on the door... using a hitTest. The door would rotate open when the button was touched.
let tappedNode = self.sceneView.hitTest(gesture.location(in: gesture.view), options: [:])
if !tappedNode.isEmpty {
let tappedName = tappedNode[0].node.name
if tappedName == "front_door" {
let doorNode = self.sceneView.scene.rootNode.childNode(withName: tappedName, recursively: true)
// rotate the door open
doorNode?.eulerAngles = SCNVector3Make( 0,0,Float(2*M_PI))
}
}

How to delay start touch event of a UISlider in iOS?

In my application, there is a UISlider which is only slidable after a long-press (let's say, after 0.1 seconds of the press). To prevent from the slider to interact immediately, I set mySlider.isUserInteractionEnabled = false as default. However, since .isUserInteractionEnabled will disable all the functions, including the long-press gesture, I use another transparent UIButton of the same size as the slider on the top of it to detect long-presses, and set mySlider.isUserInteractionEnabled = true in the callback action. This works fine, except that the UIButton must be released first and then the user tap the slider again to slide it instead of drag the slider directly within the same touch. This make the slider very inconvenient to use. Therefore, I would like to know if either:
There is a better way other than mine to make UISlider start sliding only after certain delay? I'm quite surprised that I couldn't find any solution on this. I thought this would be a common need for a slider to be locked at a certain point.
or
Following my solution, is there any way that I could start dragging the slider thumb within the same touch?
Thanks a lot for any kind of answer.
Added: My solution looks like the following: in the TableViewCell, there is a label, a slider, and an invisible button with the same size as the slider (The grey background area). I set slider attribute isUserInteractionEnabled == false, and then add gesture recogniser to manipulate the slider (such as single tap, double tap for my custom functions, and long-press gesture which enable the slider). After the button is long-pressed, the isUserInteractionEnabled of the slider will set to true until the thumb goes to the new value.
Basically I only want to disable the slider to respond too quickly for short taps, the other features of the slider would remain the same. I suppose there may be better ways to achieve this, the so far using an transparent button is the only way I could think of.
You can disable user interaction on slider and then add a gesture recogniser over it (Not exactly sure about user interaction though). Maybe do something like this
let longPress = UILongPressGestureRecognizer(target: self.slider, action: Selector("longPressAndSlide:"))
longPress.minimumPressDuration = 0
self.addGestureRecognizer(longPress)
In longPressAndSlide you can calculate the direction and delta of movement and set the value of slider accordingly.
This has been answer multiple times actually. just a better search would help you more.
Update
Check answers under - How to enable "tap and slide" in a UISlider?
Latest Update
As the comments suggest, we can add a button on top of the slider and add longPress gesture over it. The handling can be done in the handler Action for the gesture.

rotating a coordinate cross in SCNScene to mirror camera movements

I am new to SceneKit and I could use your help with the following:
I have two SCNViews
- a large one (skView) showing the scene for the user which can be manipulated by the user with the standard allowsCameraControl option enabled
- another small one (coordinateCrossView) in the left corner which shows a coordinate cross that I would like to mirror any camera navigation the user performs in the large SCNView
I implemented it by making the ViewController which holds both SCNViews a SCNRendererDelegate and by updating the cross' orientation in the renderer: updateAtTime: method like so:
- (void)renderer:(id<SCNSceneRenderer>)renderer updateAtTime:(NSTimeInterval)time {
[self.coordinateCrossView.scene.rootNode childNodeWithName:#"cross" recursively:YES].orientation = self.skView.pointOfView.orientation;
[self.coordinateCrossView setNeedsDisplay];
}
So far so good. However, this only works when the user is manipulating the large SCNView with a finger on the screen. After as swipe gesture when the finger leaves the screen the object in the large SCNView continues to rotate a bit - but the coordinate cross is not updated.
Any ideas why this behavior is not captured by the pointOfView.orientation changes?
I found out what the problem was: the small coordinateCrossView was not continuously updated and therefore even though the coordinate cross' orientation was changed, the view didn't show it - even though setNeedsDisplay was called.
I fixed the issue by setting the isPlaying property of the coordinateCrossView which forces it to be updated.

control multiple buttons with one swipe gesture swift

I have array of UIImageView that printed on the main View (as subviews) in a matrix.
That UIImageViews interact while I am tap on them (work like a pixel when I touch one of them it turn on (move from black to green)
but I want to do it with swipe gesture so i can with one swipe trigger more than one "pixel" (UIImageView)
I found this for android triggering-multiple-buttonsonclick-event-with-one-swipe-gesture
and I wonder if there is something like that in ios with swift that recognise general touch (not tap or swipe) so I can looks for it.
The main purpose of all of this is to draw "shapes" on matrix of pixels with one swipe gestures.
If there is another way that you think will help I will be happy to here about it.
Many thanks
You are looking for the UIGestureRecognizer.
With this you can add many types of gestures, as swipe, touch..etc.
You can also get position, duration, and basically all the information about it.
You can check step by step tutorial in this link.
http://www.raywenderlich.com/76020/using-uigesturerecognizer-with-swift-tutorial
And also in the apple documentation.
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIGestureRecognizer_Class/
i Manage to do the the swipe action using touchesMoved and touchesEnded
while the main idea is to invoke the UIIMageViews using the Coordinate of the touch and compare it to the to the UIImageViews Coordinates in the touchesMoved function
using flags to disable already edited UIIMageViews (while i am in the same touch session , the finger still on the screen) and refresh the UIImageViews to be editable again in the touchesEnded
func swipeTouches(touches: NSSet!) {
// Get the first touch and its location in this view controller's view coordinate system
let touch = touches.allObjects[0] as! UITouch
let touchLocation = touch.locationInView(self.view)
for pixel in pixelArrays {
// Convert the location of the obstacle view to this view controller's view coordinate system
let pixelViewFrame = self.view.convertRect(pixel.pixelImage.frame, fromView: pixel.pixelImage.superview)
// Check if the touch is inside the obstacle view
if CGRectContainsPoint(pixelViewFrame, touchLocation) {
// check if the pixel is Editable
if(!pixel.isEditable){
let index = pixel.index
pixelArrays.insert(updatePixel(index) , atIndex: index)
}
}
}
}
the only problem that i have now that if the swipe begin on one of the UIImageViews the touchesMoved function consider it the the view to looks for the coordinate and the other UIImageViews are not effected
my idea to solve it is to add layer on top all of the UIImageViews and disable the tap recognition that they alredy have and implement the tap also with the Coordinates way.
i will be happy to hear if there is another way to do it
Update :
i mange to solve the problem above by sort of what i wrote but instead of add another layer i disable the touch on all of the UIImageViews and invoke them using the Coordinates of the touch and them
many thanks

Pan Gesture recognition and UIKit Dynamics Gravity

I'm trying to make a game where objects fall from the sky (top of screen) and you have to pan an object left and right to avoid them. Pan gesture works fine but as soon as the objects (which are just other views with GCRects) start falling the pan gesture won't work. It just keeps reseting itself to its original position. To have the objects fall all I am doing is "spawning" them at the top of the screen and letting UIKit Dynamics and gravity do the rest to drop them down to the bottom. Any ideas how to have the gesture work concurrently with the falling objects?
It sounds like you have accidentally (or intentionally) added the view you want to pan manually to the animator as a dynamic item. This means that the animator is responsible for positioning it, so on every frame of the animation it puts it back where it was, because it doesn't understand that you've moved it manually. So don't add it as a dynamic item, or else your pan gesture recognizer's action method should keep calling updateItemUsingCurrentState: on the animator - that is how you tell the animator that you have moved an item manually.

Resources