How would I hide/unhide buttons when pressing on the view? - swift

I have these buttons on my cameraView that I want to hide when pressing on the view. I got that to work but I want to unhide the buttons when I press on the view again. How would I be able to do that?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
if touch?.view == self.cameraView {
flipCamera.isHidden = true
lockButton.isHidden = true
print("Hide buttons")
} else if touch?.view == self.cameraView && flipCamera.isHidden == true {
print("show buttons")
}

If you want to change the isHidden value to its opposite on each touch, you can simply use the toggle() function, which toggles a Bool value - it assigns false if the value was true and assigns true if the value was false.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
if touch?.view == self.cameraView {
flipCamera.isHidden.toggle()
lockButton.isHidden.toggle()
}
}

Related

Draggable object jumps a bit when I try to highlight a button

I have 2 UIImageView who are placed on storyboard and setup in code via frames. I have also a UIButton and an optional draggableView: UIView?. What I'm trying to do:
Drag a view - seems to be working fine
Highlight my button when I hover draggableView over it and disable highlight if we moving away from it. Highlight seems to be happening, but my draggableView goes kinda underneath a button and does a very noticeable jump into its starting position before dragging. After that if we continue dragging - position continues to update properly.
Here is the code for touches
override func viewDidLoad() {
...
img01.isUserInteractionEnabled = true
img02.isUserInteractionEnabled = true
...
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else {return}
if img01.bounds.contains(touch.location(in: img01)) {
draggableView = img01
} else if img02.bounds.contains(touch.location(in: img02)) {
draggableView = img02
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let draggableView = draggableView else {return}
guard let touch = touches.first else {return}
draggableView.center = touch.location(in: view)
if btnMain.bounds.contains(touch.location(in: btnMain)) {
print("Case 4")
btnMain.isHighlighted = true
} else {
print("Case 5")
btnMain.isHighlighted = false
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
draggableView = nil
btnMain.isHighlighted = false
}
What causes that jump to initial position and is there a way to kinda... make draggableView noticeably on top of anything? Thanks.

Tap background to dismiss TextField keyboard only if keyboard is active

I keep having an issue with a textfield I have set as a decimal keyboard, because its the decimal keyboard it doesn't have a return key so I have to tap background to dismiss it. I want to only allow it to recognize that tap if the keyboard is open. Currently it recognizes it anytime you tap the background. Any help would be awesome thanks.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
label.text = "tapped"
}
You can add this extension, it worked for me:
extension UIViewController {
func hideKeyboardWhenTappedAround() {
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(UIViewController.dismissKeyboard))
tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)
}
#objc func dismissKeyboard() {
view.endEditing(true)
}
}
Then put this self.hideKeyboardWhenTappedAround() in viewDidLoad
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
view.endEditing(true)
}

Subclassed node, but want to detect touch in the scene

I have a subclassed node called LocationNode, where touch is enabled. It looks like this.
class LocationNode: SKSpriteNode, CustomNodeEvents {
func didMoveToScene() {
self.isUserInteractionEnabled = true
}
}
I haven't overriden touchesBegan in this subclass file, because I want to control all touch events like this in the actual scene file:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touchLocation = touches.first!.location(in: self)
let touchedNode = self.atPoint(touchLocation)
//if touchedNode.name != nil {
print("touched")
//}
}
When I try do this, however, it doesn't work. How can I control touch events for a subclassed node in the scene file?
EDIT:
Here's what my override function looks like in the scene.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touchLocation = touches.first!.location(in: self)
let touchedNode = self.atPoint(touchLocation)
print("TOUCHED")
}
You could implement this code below in your custom class, in this case LocationNode, to have a "return of touches" to the parent class, then you can handle the touches in both places (also to the main scene) :
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
print("touched!")
}
guard let parent = self.parent else { return }
parent.touchesBegan(touches, with: event)
}

Touch implementation in game

I am using Swift 3 with Xcode 8 and I am trying to make simple game with SpritKit. Basically what I'm trying to do is allow player to move my sprite only left and right ( drag it on screen ) and after realising finger ( touch ended ) apply impulse on sprite. I have managed to do that BUT i want that to happen only on first touch, so after applying impulse on sprite player cannot interact with sprite anymore until some collison happens or simillar. Below is my code which works all the time not only on first touch.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches {
let location = t.location(in: self)
if player.contains(location)
{
player.position.x = location.x
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches {
if let t = touches.first {
player.physicsBody?.isDynamic = true
player.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 50))
}
}
}
As Whirlwind commented, you just need a boolean value to determine when you should control the object:
/// Indicates when the object can be moved by touch
var canInteract = true
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches {
let location = t.location(in: self)
if player.contains(location) && canInteract
{
player.position.x = location.x
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches {
if let t = touches.first && canInteract {
canInteract = false //Now we cant't interact anymore.
player.physicsBody?.isDynamic = true
player.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 50))
}
}
}
/* Call this when you want to be able to control it again, on didBeginContact
after some collision, etc... */
func activateInteractivity(){
canInteract = true
// Set anything else you want, like position and physicsBody properties
}

How do I drag and drop a sprite in Swift 3.0?

All i'm trying to do is be able to drag and drop a sprite across the screen. I've tried the following code:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in (touches ) {
let location = touch.locationInNode(self)
if ball.containsPoint(location) {
ball.position = location
}
}
}
This code does work, however, when I drag the ball quite fast, I guess it detects that the "ball" no longer contains the point "location" and the ball stops, meaning I have pick the ball up again. I want the ball to be able to respond to my touches quickly, so that the ball wont stop moving. How would I do this?
This is the correct way to do it in Sprite Kit. Like I said in my comment, you need to assign the moving node to an activate state, in this case I use a variable called movableNode to act is my activate state. When you touch the ball, it becomes activated by assigning it to movableNode. Then as you drag your finger, movableNode will go with the drag, Then once you release, you enter a deactivate state by setting movableNode to nil. Note that this code will only work on single touch applications, if you want to handle multitouch, then you need to track which touch is doing the dragging.
var movableNode : SKNode?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let location = touch.locationInNode(self)
if ball.containsPoint(location) {
movableNode = ball
movableNode!.position = location
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first where movableNode != nil {
movableNode!.position = touch.locationInNode(self)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first where movableNode != nil {
movableNode!.position = touch.locationInNode(self)
movableNode = nil
}
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
movableNode = nil
}
}
KnightOFDragon solution works just fine. I just added few lines if you don't want to move sprite centre position to position where your finger touched the screen and you would like to move sprite from its centre original position.
var movableNode : SKNode?
var ballStartX: CGFloat = 0.0
var ballStartY: CGFloat = 0.0
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let location = touch.location(in: self)
if (map?.contains(location))! {
movableNode = ball
ballStartX = (movableNode?.position.x)! - location.x // Location X of your sprite when touch started
ballStartY = (movableNode?.position.y)! - location.y // Location Y of your sprite when touch started
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first, movableNode != nil {
let location = touch.location(in: self)
movableNode!.position = CGPoint(x: location.x+ballStartX, y: location.y+ballStartY) // Move node around with distance to your finger
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if let _ = touches.first, movableNode != nil {
movableNode = nil
}
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
movableNode = nil
}
I have an implementation where I've subclassed a UIImageView and called it a "DraggableImage"
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
originalPosition = self.center
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let position = touch.location(in: self.superview)
self.center = CGPoint(x: position.x, y: position.y)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
self.center = originalPosition
}