Custom Swift UIGestureRecognizer does not call assigned action - ios

I have a UIViewController with a custom UIGestureRecognizer added to one of its views. The problem is that i get all the touch printlines from my DialGestureRecognizer but the handleDial action is never called. (iOS 8 / Xcode 6.1.1) What did i do wrong? Any help appreciated.
#IBOutlet var dialView:UIView?
override func viewDidLoad() {
super.viewDidLoad()
if let _dialView = dialView? {
let recognizer = DialGestureRecognizer(target:self, action:"handleDial:")
_dialView.addGestureRecognizer(recognizer)
}
func handleDial(recognizer:DialGestureRecognizer) {
println("handleDial")
}
}
The custom (stripped down) UIGestureRecognizer looks like this
class DialGestureRecognizer:UIGestureRecognizer {
func touchesBegan(touches:NSSet!, withEvent event:UIEvent!) {
println("touchesBegan")
}
func touchesMoved(touches:NSSet!, withEvent event:UIEvent!) {
println("touchesMoved")
}
func touchesEnded(touches:NSSet!, withEvent event:UIEvent!) {
println("touchesEnded")
}
}

You have to trigger the selector from inside the gesture recogniser.
To trigger the selector, you have to modify the state property of the UIGestureRecognizer. This property is readonly.
For modifying that you have to add a BridgingHeader as follows.
You need to have or create a -Bridging-Header.h file to import Objective C headers such as the one you want.
If you don't already have a bridge header file in your app, the easiest way to get one is to add an objc class to your project, and xcode will ask if you want one, then creates the file and ties it into the settings for you. You can then delete the objc class.
Add the next line to the Bridging Header file.
#import <UIKit/UIGestureRecognizerSubclass.h>
Then you can modify the self.state property to get the events fired.
override func touchesBegan(touches:NSSet!, withEvent event:UIEvent!) {
println("touchesBegan")
self.state = UIGestureRecognizerState.Began
}
For more information read
http://www.raywenderlich.com/76020/using-uigesturerecognizer-with-swift-tutorial

Related

Shake gesture not working iOS

I have used collectionView and also implemented pull to sync (pull_Down_To_Get_Data_From_Server) in my ViewController(named : "DashboardViewController"). I tried the shake gesture
code(given below) in my DashboardViewController and its not working but similar code is working in another viewController of same app.
I used the canBecomeFirstResponder in viewDidLoad in first try and in viewDidAppear secondly but it was also useless.
Requirement:
Actualy i want to know the cases(if any) in which ".motionShake" event do not trigger directly and we have to implement another way? Also that i did not find anything fruitful
on google.
Image of storyboard may help in understanding all the utilities used
override func viewDidLoad() {
// call super
super.viewDidLoad()
self.becomeFirstResponder() // for shake gesture detection
}
// it will make first responder to detect shake motion event
override var canBecomeFirstResponder: Bool {
get {
return true
}
}
// get detection of shake motion event
override func motionEnded(_ motion: UIEventSubtype, with event: UIEvent?) {
if motion == .motionShake
{
print("Shake detected")
}
}
We ran into something similar while working on Yoshi
We ended up creating an extension on UIWindow, that contained the motionBegan event and forwarded the event. Not sure what caused it, but it seemingly broke with swift 3.0.

Best way to perform action on 3D Touch on UIButton

I have a number of UIButton instances in a UIViewController and I want to perform a couple of actions when any of these buttons are pressed with pressure (all the way down), I don't know the exact term here (force touch maybe?).
So when UIButton is pressured, I want to give haptic feedback via vibration, change the button image source and do some other stuff. Then when the pressure is released I want to restore the button image source to the normal state and do some more stuff.
What is the easiest way to do this?
Should I make my own custom UIButton like below or are there methods that can be overridden for 3D touch "pressed" and "released".
This is my custom UIButton code so far. Should I determine, by trial and error, what the maximum force should be? Also how do I change the source of the image for each button in the easiest way possible?
import AudioToolbox
import UIKit
class customButton : UIButton {
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in touches {
print("% Touch pressure: \(touch.force/touch.maximumPossibleForce)");
if touch.force > valueThatIMustFindOut {
AudioServicesPlayAlertSound(SystemSoundID(kSystemSoundID_Vibrate))
// change image source
// call external function
}
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
print("Touches End")
// restore image source
// call external function
}
}
Please note that I am new to Swift so I would like to use the graphical interface in Xcode to create the user interface as much as possible. So I would like to avoid creating the UI from the code.
As for the force touch - you need to detect if it's available first:
func is3dTouchAvailable(traitCollection: UITraitCollection) -> Bool {
return traitCollection.forceTouchCapability == UIForceTouchCapability.available
}
if(is3dTouchAvailable(traitCollection: self.view!.traitCollection)) {
//...
}
and then in e.g. touchesMoved it will be available as touch.force and touch.maximumPossibleForce
func touchMoved(touch: UITouch, toPoint pos: CGPoint) {
let location = touch.location(in: self)
let node = self.atPoint(location)
//...
if is3dTouchEnabled {
bubble.setPressure(pressurePercent: touch.force / touch.maximumPossibleForce)
} else {
// ...
}
}
Here's the more detailed example with code samples:
http://www.mikitamanko.com/blog/2017/02/01/swift-how-to-use-3d-touch-introduction/
It's also a good practice to react on such "force touches" with haptic/taptic feedback, so user will experience the touch:
let generator = UIImpactFeedbackGenerator(style: .heavy)
generator.prepare()
generator.impactOccurred()
you might want to take a look at this post for details:
http://www.mikitamanko.com/blog/2017/01/29/haptic-feedback-with-uifeedbackgenerator/

Hide keyboard on tap on each view - Swift

I'm not going to ask how to hide the keyboard after you are done with editing a textField. My question is : Is there a way to do this on each view ? (like a setting) or do I need to write the two following functions and set the delegate properly every time ?
func textFieldShouldReturn(textField: UITextField) -> Bool // called when 'return' key pressed. return NO to ignore.
{
textField.resignFirstResponder()
return true;
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.view.endEditing(true)
}
I'm developing an app with a lot of textfields (and also views) so I try to avoid redundance code. What is the best solution to avoid this repetition?
Thank you!
You can create your own text field, which is subclass of UITextField. See the simple custom UITextField below:
import UIKit
class CustomTextField: UITextField, UITextFieldDelegate {
override func awakeFromNib() {
super.awakeFromNib()
self.delegate = self
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
self.resignFirstResponder()
return true
}
}
Use your custom text field name to Custom Class in your Storyboard.
See my example at Github
The easiest thing to do, is put one giant invisible button the size of the screen underneath your text fields, then when a non text field is tapped, you call the invisible button action to close it. If this does not apply in your scenario please let me know.
Create an IBAction method to dismiss keyboard
#IBAction func backgroundTapped (sender: UIView)
{
sender.endEditing(true)
}
Change the class of your UIView to UIControl which contains the textfields in storyboard (You can even do that to your view of the viewcontroller as shown)
It looks like this:
Now you can connect the IBAction to the Touch Up Inside event of this view, in the storyboard, as shown.

Creating a button using SKLabelNode as a parent in Swift SpriteKit

I'm trying to create a subclass of SKLabelNode for a button in SpriteKit. I tried to create a button using SKLabelNode as a parent, so I can use everything I know about labels while creating my buttons (font, text size, text color, position, etc).
I've looked into Swift Spritekit Adding Button Programaticly and I'm using the basis of what that is saying, but rather I'm making a subclass instead of a variable, and I'm creating the button using a label's code. The subclass has the added function that will allow it to be tapped and trigger an action.
class StartScene: SKScene {
class myButton: SKLabelNode {
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if myButton.containsPoint(location) {
// Action code here
}
}
}
}
override func didMoveToView(view: SKView) {
let startGameBtn = myButton(fontNamed: "Copperplate-Light")
startGameBtn.text = "Start Game"
startGameBtn.fontColor = SKColor.blackColor()
startGameBtn.fontSize = 42
startGameBtn.position = CGPointMake(frame.size.width/2, frame.size.height * 0.5)
addChild(startGameBtn)
}
}
My error is in: if myButton.containsPoint(location)
The error reads: Cannot invoke 'containsPoint' with an argument list of type '(CGPoint)'
I know it has to do something with my subclass, but I have no idea what it is specifically.
I also tried putting parentheses around myButton.containsPoint(location) like so:
if (myButton.containsPoint(location))
But then the error reads: 'CGPoint' is not convertible to 'SKNode'
Thanks
I have an alternative solution that would work the same way.
Change the following code
if myButton.containsPoint(location) {
To this and it should compile and have the same functionality
if self.position == location {

Swift Delegate Not Being Called

I have a view with a delegate that I want to have call numpadView(numpadView:) in GameController upon button press, however I can't get it to work. The overload of touchesBegan() works fine, it's really the line with pressDelegate?.numpadView(self) which doesn't call the delegate function in the GameController class. I'm stumped as to what's missing to get it to work?
I cleaned the code to leave only the essential related to the problem for simplicity.
NumpadView.swift
protocol NumpadPressDelegateProtocol {
func numpadView(numpadView: NumpadView)
}
class NumpadView: UIButton{
var pressDelegate: NumpadPressDelegateProtocol?
init(char: Character) {
let frame = CGRectMake(160, 100, 50, 50)
super.init(frame:frame)
self.setTitle("\(char)", forState: UIControlState.Normal)
self.userInteractionEnabled = true
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
pressDelegate?.numpadView(self)
}
}
GameController.swift
class GameController: NumpadPressDelegateProtocol {
func numpadView(numpadView: NumpadView) {
//do something
}
}
Declaring GameController as NumpadPressDelegateProtocol is not enough for you to get a callback. You also need to set the pressDelegate of the NumpadView instance inside the Gamecontroller. Assuming numpadView is the instance variable be it IBOutlet or not, you have to set the delegate like
Inside GameController init
numpadView.pressDelegate = self
Have you set the pressDelegate property to something? Nothing is assigned to it in the code you've shown. Do you assign something to it elsewhere in your code?

Resources