Is it possible to change value by scrolling OSX trackpad (Swift)? - macos

Is it possible to change a value in Cocoa depending on the direction of the trackpad scroll/ magic mouse 'wheel' scroll etc.
For example
var value = 0
func startsScrolling() {
if direction == up {
value += 5
} else if direction == down {
value -= 5
}
}
This would continuous so as you scroll up on the trackpad the direction is down and so it takes 5 off every time the fingers move up, and vice versa.
Thanks and sorry for the bad pseudo code.

You can create a custom window and override scrollWheel NSEvent. You can check the scrollingDeltaX and scrollingDeltaY properties.
class CustomWindow: NSWindow {
override func scrollWheel(theEvent: NSEvent) {
println( "Mouse Scroll scrollingDeltaX = \(theEvent.scrollingDeltaX)" )
println( "Mouse Scroll scrollingDeltaY = \(Int(theEvent.scrollingDeltaY))" )
}
}
If you are using storyboards you have to override scrollWheel NSEvent of your viewController:
import Cocoa
class ViewController: NSViewController {
#IBOutlet weak var strDeltaX: NSTextField!
#IBOutlet weak var strDeltaY: NSTextField!
#IBOutlet weak var strScrollingDeltaX: NSTextField!
#IBOutlet weak var strScrollingDeltaY: NSTextField!
#IBOutlet weak var strValueX: NSTextField!
#IBOutlet weak var strValueY: NSTextField!
var xValue:CGFloat = 0
var yValue:CGFloat = 0
override func viewDidLoad() {
super.viewDidLoad()
}
override var representedObject: AnyObject? {
didSet {
}
}
override func scrollWheel(theEvent: NSEvent) {
strDeltaX.stringValue = "deltaX: \(theEvent.deltaX)"
strDeltaY.stringValue = "deltaY: \(theEvent.deltaY)"
strScrollingDeltaX.stringValue = "scrollingDeltaX: \(theEvent.scrollingDeltaX)"
strScrollingDeltaY.stringValue = "scrollingDeltaY: \(theEvent.scrollingDeltaY)"
xValue += theEvent.scrollingDeltaX
yValue += theEvent.scrollingDeltaY
strValueX.stringValue = "xValue: \(xValue)"
strValueY.stringValue = "yValue: \(yValue)"
}
}

First you need to add a scroll view to your ViewController and link it. You can make it transparent if you don't want it to show. If you have buttons on your ViewController you can send it to back. I've converted code from objective-c. More power to you :)
var pointNow: CGPoint?
func scrollViewWillBeginDragging(scrollView: UIScrollView) {
pointNow = scrollView.contentOffset
}
func scrollViewDidScroll(scrollView: UIScrollView) {
if scrollView.contentOffset.y < pointNow!.y {
println("down")
}
else {
if scrollView.contentOffset.y > pointNow!.y {
println("up")
}
}
}

Related

Xcode 14 IBDesignable preview crashes, however IBInspectable properties appear and work as expected

I am making a reusable view to draw a playing card. The reusable view (which consists of an xib and swift files). The screen with this reusable view build & runs on the simulator without any issues, however in the XIB file, the preview doesn't work. In attributes inspector it says "Designables: Error", and inside the content view, where I want to preview the reusable view, it says "NameOfMyReusableView ‼️Designable".
Here's the reusable view code:
#IBDesignable class PlayingCardView: UIView {
#IBOutlet var contentView: UIView!
#IBOutlet private weak var cardBackground: UIImageView!
#IBOutlet private weak var topLeadingLabel: UILabel!
#IBOutlet private weak var bottomTrailingLabel: UILabel!
#IBInspectable var rank: String = "" {
didSet {
topLeadingLabel.text = rank
bottomTrailingLabel.text = rank
}
}
#IBInspectable var suit: String = "" {
didSet {
topLeadingLabel.text?.append("\n\(suit)")
bottomTrailingLabel.text?.append("\n\(suit)")
}
}
private var isUpsideDown: Bool = false {
didSet {
if isUpsideDown {
topLeadingLabel.alpha = 0
bottomTrailingLabel.alpha = 0
cardBackground.alpha = 1
} else {
topLeadingLabel.alpha = 1
bottomTrailingLabel.alpha = 1
cardBackground.alpha = 0
}
}
}
override init(frame: CGRect) {
super.init(frame: frame)
loadNibFile()
setup()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
loadNibFile()
setup()
}
func setup() {
isUpsideDown = false
contentView.layer.cornerRadius = 16
topLeadingLabel.text = "5\n❤️"
bottomTrailingLabel.text = "5\n❤️"
bottomTrailingLabel.transform = CGAffineTransform.identity.rotated(by: CGFloat.pi)
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(flipCard(_:)))
contentView.addGestureRecognizer(tapGesture)
}
private func loadNibFile() {
Bundle.main.loadNibNamed("PlayingCardView", owner: self)
addSubview(contentView)
contentView.frame = self.bounds
contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
contentView.clipsToBounds = true
}
#objc private func flipCard(_ sender: UITapGestureRecognizer) {
isUpsideDown.toggle()
}
}
I tried clean build, but obviously it didn't help.

swift 4- Save the last data of a text field in a label so that they are displayed when the app is restarted

I have a problem, I want to create a small app in which data in a formula can be charged.
Currently the data from three ViewControllers and one PickerViewController will be given back to the first ViewController.
That works very well too.
Now I want that the data at the start not on "nil" set but have a certain value.
Thereafter, the data entered last should reappear when the app is restarted.
I would like to apologize for my english, it is not my preferred language ...
Here is a part of my code how I wrote it
Main ViewController:
import UIKit
class RecivingViewController: UIViewController, SendDataBack, SendDataBack2, SendDataBack3, SendDataBack4 {
#IBOutlet weak var recivingData: UILabel!
#IBOutlet weak var recivingData2: UILabel!
#IBOutlet weak var recivingData3: UILabel!
#IBOutlet weak var recivingData4: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
func userData(data: String) {
recivingData.text = data
}
func userData2(data: String) {
recivingData2.text = data
}
func userData3(data: String) {
recivingData3.text = data
}
func PickerData(data: String){
recivingData4.text = data
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "view1" {
let SendingVC: SendingViewController = segue.destination as! SendingViewController
SendingVC.delegate = self
}
if segue.identifier == "view2" {
let SendingVC2: Sending2ViewController = segue.destination as! Sending2ViewController
SendingVC2.delegate = self
}
if segue.identifier == "view3" {
let SendingVC3: Sending3ViewController = segue.destination as! Sending3ViewController
SendingVC3.delegate = self
}
if segue.identifier == "picker" {
let SendingVC4: PickerViewController = segue.destination as! PickerViewController
SendingVC4.delegate = self
}
}
}
one of the other ViewControllers:
import UIKit
protocol SendDataBack {
func userData(data: String)
}
class SendingViewController: UIViewController {
#IBOutlet weak var DataTxt: UITextField!
var delegate: SendDataBack? = nil
#IBAction func done(_ sender: Any) {
if delegate != nil {
if DataTxt.text != nil {
let data = DataTxt.text
delegate?.userData(data: data!)
dismiss(animated: true, completion: nil)
}
}
}
In order to see data after app is restarted you should use user defaults.
For saving data
UserDefaults.standard.set(newValue, forKey: "data")
For loading data in your view controller, if it's first load, when data is nil
UserDefaults.standard.string(forKey: "data")

Reading right mouse clicks number of clicks

I have been experimenting with mouse clicks. I am ok with left mouse clicks getting raw values etc etc. I now want to add right mouse clicks. I have setup a basic example. What i would like to achieve if there is one mouse right click it performs one function, and if there is two mouse right clicks it performs a different function. The problem is if you do two mouse clicks it obviously cannot differentiate between the two and so fire the one mouse click function before performing the second mouse function.
I was thinking of maybe using a timer of some sort to record the number of click. But i end up going round in circles as i just seem to start the timers over and over. I'm hoping some one might help. thanks for reading here is the code.
Xcode 8 Swift 3 Mac OSX Sierra NOT IOS.. NOT IOS
import Cocoa
class MainWindowController: NSWindowController {
#IBOutlet weak var MyView: NSView!
override func windowDidLoad() {
super.windowDidLoad()
//Initialize mouse for Right Click numberOfClicksRequired = 1
let recogRightClick1 = NSClickGestureRecognizer(target: self, action: #selector(oneMouseClick))
recogRightClick1.buttonMask = 0x2
recogRightClick1.numberOfClicksRequired = 1
MyView.addGestureRecognizer(recogRightClick1)
//Initialize mouse for Right ClicknumberOfClicksRequired = 2
let recogRightClick2 = NSClickGestureRecognizer(target: self, action: #selector(twoMouseClick(myrec:myRightClick:)))
recogRightClick2.buttonMask = 0x2
recogRightClick2.numberOfClicksRequired = 2
MyView.addGestureRecognizer(recogRightClick2)
}//EO Overide
func oneMouseClick(myrec: NSPanGestureRecognizer,myRightClick:NSClickGestureRecognizer){
let rightClick = myRightClick.state.rawValue
print("oneMouseClick",rightClick)
}
func twoMouseClick(myrec: NSPanGestureRecognizer,myRightClick:NSClickGestureRecognizer){
let rightClick = myRightClick.state.rawValue
print("twoMouseClick",rightClick)
}
}//EnD oF thE wORld
UPDATE
I have re generated the code following the advice given. Now the code reflects more of what i wanted to do. My only problem is that I would like all the mouse operations to be triggered only inside 'myView' rather than within the main window. I thought it might have something to do with first responder but that doesn't seem to work. Again any thought would be appreciated. Please excuse any bad code i'm self taught.
Xcode 8 Swift 3 Mac OSX Sierra NOT IOS.. NOT IOS
import Cocoa
class MainWindowController: NSWindowController {
#IBOutlet weak var myView: NSView!
var mouseX:CGFloat = 0
var mouseY:CGFloat = 0
override func windowDidLoad() {
myView.window?.becomeFirstResponder()
myView.window?.acceptsMouseMovedEvents = true
super.windowDidLoad()
myView.wantsLayer = true
myView.layer?.backgroundColor = CGColor(red: 0.05, green: 0.57, blue: 0.80, alpha: 0.6)
NSEvent.addLocalMonitorForEvents(matching:.leftMouseDown){
self.mouseEventFunction(data: 1)
return $0
}
NSEvent.addLocalMonitorForEvents(matching:.leftMouseUp){
self.mouseEventFunction(data:2)
return $0
}
NSEvent.addLocalMonitorForEvents(matching:.rightMouseDown){
self.mouseEventFunction(data: 3)
return $0
}
NSEvent.addLocalMonitorForEvents(matching:.rightMouseUp){
self.mouseEventFunction(data: 4)
return $0
}
NSEvent.addLocalMonitorForEvents(matching:.mouseMoved) {
self.mouseX = NSEvent.mouseLocation().x
self.mouseY = NSEvent.mouseLocation().y
return $0 }
}//EO Overide
func mouseEventFunction (data: Int){
switch data{
case 1 :
print("LeftMouseDown")
case 2 :
print("LeftMouseUp")
case 3 :
print("RightMouseDown")
case 3 :
print("RightMouseUP")
default: break
}
if data == 1 {print("mouseX",mouseX,"mouseY",mouseY)}
}//eo mouseEvent
}//EnD oF thE wORld
UPDATE 2
I have now updated subClassing the view controller, so the mouse clicks are now only working in myView. I'm still having problems with 'func mouseDragged' What i need to achieve is the bottom left of my view is x = 0 and Y = 0. I had a try with converting but thats not working. hoping someone might guide me. thanks for reading here is the updated code.
Xcode 8 Swift 3 Mac OSX Sierra NOT IOS.. NOT IOS
import Cocoa
class MainWindowController: NSWindowController {
#IBOutlet weak var myView: NSView!
override func windowDidLoad() {
myView.window?.becomeFirstResponder()
myView.window?.acceptsMouseMovedEvents = true
window?.contentView?.addSubview(myView)
super.windowDidLoad()
}//EO Overide
}//EnD oF thE wORld
class testView: NSView {
override func draw(_ dirtyRect: NSRect) {
let backgroundColor = NSColor.lightGray
backgroundColor.set()
NSBezierPath.fill(bounds)
}
override func mouseDragged(with theEvent: NSEvent) {
let myLocationInWindow = theEvent.locationInWindow
let location = convert(myLocationInWindow, to: self)
Swift.print("myLocationInWindow",myLocationInWindow,"location",location)
}
override func mouseDown(with theEvent: NSEvent) {
Swift.print("mouseDown")
}
override func mouseUp(with theEvent: NSEvent) {
Swift.print("mouseUp clickCount: \(theEvent.clickCount)")
}
}//eo testView
To define mouse inside view you use
let myLocationInWindow = theEvent.locationInWindow
let location = convert(myLocationInWindow, from: nil)
where nil is the window
here is the final code
import Cocoa
class MainWindowController: NSWindowController {
#IBOutlet weak var myView: NSView!
override func windowDidLoad() {
super.windowDidLoad()
}//EO Overide
}//EnD oF thE wORld
class testView: NSView {
override func draw(_ dirtyRect: NSRect) {
let backgroundColor = NSColor.lightGray
backgroundColor.set()
NSBezierPath.fill(bounds)
}
override func mouseDragged(with theEvent: NSEvent) {
let myLocationInWindow = theEvent.locationInWindow
let location = convert(myLocationInWindow, from: nil)
Swift.print("location",location)
}
override func mouseDown(with theEvent: NSEvent) {
Swift.print("mouseDown")
}
override func mouseUp(with theEvent: NSEvent) {
Swift.print("mouseUp clickCount: \(theEvent.clickCount)")
}
}//eo testView

Swift 2.0 animating images

Trying animate series of images in swift 2.0 but following the video tutorials like https://www.youtube.com/watch?v=PSny6un3VUw the method that this guy uses are no longer relevant and swift 2.0 no longer allows arrays to be setup in such means. The basic code this guy used is as follows:
class ViewController: UIViewController: {
#IBOutlet var myImageView: UIImageView
#IBOutlet var animationBtn: UIButton
var imageList = UIImage[]() // no longer valid?
#IBAction func animationBtnClicked(sender: AnyObject) {
startAnimation
}
override func viewDidLoad() {
for i in 1...13
{
let imageName = "\(1)"
imageList += UIImage(named: imageName) //line no longer works
}
}
func startAnimation() -> Void
{
myImageView.animationImages = imageList
myImageView.startAnimation()
}
Anyone know a better way in swift 2.0 to animate images or anyway in general how to do this?
I hope I will help you
#IBOutlet var myImageView: UIImageView!
#IBOutlet var animationBtn: UIButton!
var imageList = [UIImage]()
imageList.append(UIImage(named: imageName))
or
imageList += [UIImage(named: imageName)]

Hitting Return to save Text Input

I have a text field on my xcode project, how can I do to save the user input just by hitting return on the keyboard, instead of using a button to save it?
ViewController with the new code:
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var textFieldInput: UITextField!
#IBOutlet weak var iphoneSaveCharName: UIButton!
#IBOutlet weak var charOne: UIButton!
#IBOutlet weak var charTwo: UIButton!
#IBOutlet weak var charThree: UIButton!
#IBOutlet weak var charFour: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// #IBAction func iphoneSaveTextInput(sender: UIButton) -> Void{
//
// let textData = textFieldInput.text
// textFieldInput.hidden = true
// iphoneSaveCharName.hidden = true
// }
var savedText: String!
func textFieldShouldReturn(textFieldInput: UITextField) -> Bool {
savedText = textFieldInput.text
println(savedText)
textFieldInput.resignFirstResponder()
return false
}
#IBAction func editText(sender: AnyObject) {
if sender is UILongPressGestureRecognizer &&
sender.state == UIGestureRecognizerState.Began {
textFieldInput.hidden = false
iphoneSaveCharName.hidden = false
let button = sender.view as UIButton
if button.tag == 1{
charOne.setTitle(savedText, forState: .Normal)
} else if button.tag == 2{
charTwo.setTitle(savedText, forState: .Normal)
} else if button.tag == 3{
charThree.setTitle(savedText, forState: .Normal)
} else if button.tag == 4{
charFour.setTitle(savedText, forState: .Normal)
}
}
}
}
The editText function is a long press gesture recognizer that checks what button is being long pressed.
Set the view controller as a text field delegate and add the appropriate delegate method.
class viewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var textField: UITextField!
var savedText: String!
func textFieldShouldReturn(textField: UITextField) -> Bool {
savedText = textField.text
textField.resignFirstResponder()
return false
}
}

Resources