From the developer docs by apple here, I came across this.
Instead of handling a gesture, you could choose to track and handle the “raw” touches that make up the gesture.
Examples in the documentation are given for Objective-C however not for Swift. How can I track and handle these "raw" touches in Swift globally? Not just within an NSView?
My class:
import Cocoa
import Security
import AppKit
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
#IBOutlet weak var window: NSWindow!
#IBOutlet weak var dropMenu: NSMenu!
#IBOutlet weak var resetView: NSView!
#IBOutlet weak var resetWindow: NSPanel!
#IBOutlet weak var keyLabel: NSTextField!
let statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(-1);
func applicationDidFinishLaunching(aNotification: NSNotification) {
NSApp.setActivationPolicy(NSApplicationActivationPolicy.Accessory)
let menuIcon = NSImage(named: "menuIcon")
menuIcon?.template = true;
statusItem.image = menuIcon;
statusItem.menu = dropMenu;
}
#IBAction func quit(sender: NSMenuItem) {
NSApplication.sharedApplication().terminate(self)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch: AnyObject! in touches {
let touchLocation = touch.locationInNode(self)
//Use touchLocation for example: button.containsPoint(touchLocation) meaning the user has pressed the button.
}
}
}
Updated Again, NSEvent:
(touchesBegan UIEvent etc is for iOS, MacOS is different and uses NSEvent)
NSEvent is what you want to look into, where you can use mouseDown, mouseUp, mouseMove etc and then get the cursor point:
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSResponder_Class/index.html#//apple_ref/occ/instm/NSResponder/mouseDown:
Swift Example of mouseDown:
override func mouseDown(event: NSEvent) {
let point: NSPoint = event.locationInView
print("X: \'point.x'")
print("Y: \'point.y'")
}
Objc Example:
- (void)mouseDown:(NSEvent *)event {
NSLog( #"mouse down event: %#", event );
NSPoint point = [event locationInWindow];
NSLog( #"mouseDown location: (%d,%d)", point.x, point.y );
}
Hope this helps.
Related
newbie swift programmer here that needs help with something that probably is trivial...
This is in different File, different View:
class CanvasContainerView: UIView {
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
// here are all of the calculations that lead to scoreString being calculated..
var scoreString = round(1000 * accuracyTotal / angleTotal)
}
//lots of other code
}
I need the value of my calculated "scoreString" to be accessible in a different file, different controller. How can i pass this value through if i'm using TouchesMoved function ? Below is how i tried to implement it in different file but failed miserably as there is no "scoreString" in scope:
import UIKit
class CanvasMainViewController: UIViewController {
#IBOutlet weak var ScoreText: UITextField!
/// Prepare the drawing canvas.
/// - Tag: CanvasMainViewController-viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
ScoreText.text = "\(CanvasContainerView.touchesMoved(scoreString))"
}
//lots of code
}
In the end i want my score to be displayed on top of the screen:
So i am aware that there are questions like this already on Stack but whats specific about my question is that im using this "touchesMoved" overriden function that doesn't let me return any value. It shouts it needs void return type.
I will be very thankful for any help.
Using a delegate is the good method :
// the protocol (ie the method called by container view in the controller)
protocol CanvasContainerViewDelegate {
func scoreUpdate(fromView view:CanvasContainerView, newScore: Double)
}
class CanvasContainerView: UIView {
// the delegate that will be called
var delegate: CanvasContainerViewDelegate?
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
// here are all of the calculations that lead to scoreString being calculated..
var scoreString = round(1000 * accuracyTotal / angleTotal)
// Telling the delegate the new score value
delegate?.scoreUpdate(fromView: self, newScore: scoreString)
}
//lots of other code
}
class CanvasMainViewController: UIViewController, CanvasContainerViewDelegate {
#IBOutlet weak var ScoreText: UITextField!
#IBOutlet weak var containerView: CanvasContainerView!
/// Prepare the drawing canvas.
/// - Tag: CanvasMainViewController-viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
// set the controller as a delegate of the view
containerView.delegate = self
}
// Update the score (called by the view)
func scoreUpdate(fromView view: CanvasContainerView, newScore: Double) {
ScoreText.text = "\(newScore)"
}
//lots of code
}
Apparently adding public in front of the var declared on top of the file solved the problem. Thank you for participation in trying to help me.
I am a beginner so bear with me.
I created a basic timer app and rounded the corners of two buttons. The button was still clickable outside of the circle, I needed to fix that so I found a solution online that said to insert the code into the UIButton's subclass or extension. I found solutions for both ways and chose extension option because the code was easier to read and I could understand it better.
The issue now is that I have a third UIButton that is being affected by the extension and I would like to exclude it. I'm not sure if this is even practical (or possible) so please correct me if there is a better way to approach this. The button I need to exclude from the extension is resetButton.
import UIKit
extension UIButton {
open override func draw(_ rect: CGRect) {
self.layer.cornerRadius = 50.0
self.layer.masksToBounds = true
//exclude resetButton???
}
private var touchPath: UIBezierPath {return UIBezierPath(ovalIn: self.bounds)}
open override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
return touchPath.contains(point)
}
}
class ViewController: UIViewController {
#IBOutlet weak var label: UILabel!
#IBOutlet weak var startButton: UIButton!
#IBOutlet weak var stopButton: UIButton!
#IBOutlet weak var resetButton: UIButton!
var timeRemaining: Int = 10
var timer: Timer?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//// Moved to an extension in order to
//// remove the clickable areas outside
//// of the circle
//startButton.layer.cornerRadius = 50.0
//stopButton.layer.cornerRadius = 50.0
}
#IBAction func start(_ sender: Any) {
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(step), userInfo: nil, repeats: true)
}
#IBAction func stop(_ sender: Any) {
timer?.invalidate()
}
#IBAction func reset(_ sender: Any) {
timer?.invalidate()
timeRemaining = 10
label.text = "\(timeRemaining)"
}
#objc func step() {
if timeRemaining > 0 {
timeRemaining -= 1
} else {
timer?.invalidate()
}
label.text = "\(timeRemaining)"
}
}
For your case, extension is not the right option as the methods invoked from extension will apply to the type itself (all UIButton objects in this case).
One option for you is to make a subclass of UIButton instead of extension. Something like this:
class RoundedButton: UIButton {
open override func draw(_ rect: CGRect) {
self.layer.cornerRadius = 50.0
self.layer.masksToBounds = true
}
private var touchPath: UIBezierPath {return UIBezierPath(ovalIn: self.bounds)}
open override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
return touchPath.contains(point)
}
}
And hence you can select the buttons that should inherit the custom layout from the class above:
#IBOutlet weak var startButton: RoundedButton!
#IBOutlet weak var stopButton: RoundedButton!
#IBOutlet weak var resetButton: UIButton! // Will not get the style applied for startButton and stopButton
I have an IBOutlet-connected UIView object (innerView) sitting over view controller (UIViewController)'s view. I want to let the user rotate innerView with their finger. So I have a subclass (TouchView) of UIView set to innerView's class. As the user rotates the view object, I want the view controller to receive a value from TouchView. And what I have is the following.
// UIView
protocol TouchDelegate: class {
func degreeChanged(degree: Double)
}
class TouchView: UIView {
weak var delegate: TouchDelegate? = nil
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let aTouch: AnyObject = touches.first! as UITouch
let newLoc = aTouch.location(in: self.superview)
...
...
let degree = { (radians: Double) -> Double in
return radians * 180 / M_PI
}
self.delegate?.degreeChanged(degree: degree)
}
}
// UIViewController
class ViewController: UIViewController, TouchDelegate {
#IBOutlet weak var innerView: UIView!
// MARK: - View
override func viewDidLoad() {
super.viewDidLoad()
let touchView = TouchView()
touchView.delegate = self
}
// MARK: - From TouchView
func degreeChanged(degree: Double) {
print(degree) // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< no call
}
}
Well, the view controller never receives a delegate call from TouchView. What am I doing wrong? Thank you for your help.
I see 2 problems
You created a new instance of touchView and did not add it into your view controller's views
Your innerView is not an instance of touchView and its delegate is not set
My approach to your situation would look something like this:
// UIViewController
class ViewController: UIViewController, TouchDelegate {
#IBOutlet weak var innerView: TouchView!
// MARK: - View
override func viewDidLoad() {
super.viewDidLoad()
innerView.delegate = self
}
// MARK: - From TouchView
func degreeChanged(degree: Double) {
print(degree) // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< no call
}
}
I would like to ask you about moving UIImageView.
Let’s imagine that an UIImageView is at location X1. If I want to move imv to location X2 using drag event, How can I implement it?
Please give me advice.
Thanks for reading.
I have refered to How to drag UIImageView using touches method
import UIKit
class ViewController: UIViewController {
#IBOutlet var imgView: UIImageView!
var imgMarker:UIImage?
var location = CGPoint()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
imgMarker = UIImage(named: "marker.png")
imgView.image = imgMarker
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?){
if let touch = touches.first {
location = touch.location(in: self.view)
imgView.center = location
}
}
}
I am working on a program where I have various UITextViews. The problem I am having is that I cannot detect when the user has tapped outside of the UITextView so that I can hide the keyboard. I have tried various actions, but none of them work.
Code I am using with actions:
#IBAction func touchOutsideTextField(sender: UITextField)
{
sender.resignFirstResponder()
}
What should I be doing to hide the keyboard instead of this?
You can use UITapGestureRecognizer For that.
add TapGesture into View and when View is tapped that time keyBoard will hide.
Here is the sample code for you.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var text: UITextView!
#IBOutlet weak var text2: UITextView!
#IBOutlet weak var text3: UITextView!
#IBOutlet weak var text4: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
let aSelector : Selector = "touchOutsideTextField"
let tapGesture = UITapGestureRecognizer(target: self, action: aSelector)
tapGesture.numberOfTapsRequired = 1
view.addGestureRecognizer(tapGesture)
}
func touchOutsideTextField(){
self.view.endEditing(true)
}
}
Or you can use touchesBegan method for it add this code if you want to try this way.
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
self.view.endEditing(true)
}
With this code you don't need to add UITapGestureRecognizer.
You can choose one of this option.
For those still using Obj C here is the translation:
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
[self.view endEditing:TRUE];
}
Apple says in their documentation that if you omit the call to super, then you must also override the other touch methods...even if you don't use them. For more on that here is the link: touchesBegan:withEvent: