UILongPressGestureRecognizer and UITapGestureRecognizer - swift

I am quite new to Swift and I am fascinated to the potential of distinguish these two gesture for a button.
I am writing my first app in xCode and I am near to conclude that. As a last step I want to implement two different actions for a button depending on a long press or a tap.
I have constructed the app as follows. I have several buttons connected to one IBAction and distinguished them using tags.
coming to the tag of the one of the two buttons on which I need the long press action I don't know how to continue.
Do you have some suggestion?
Thank you so much
func longTap() {
if (resultDisplay.text != ""){
storedVariableA = String(result)
eraseAll()
}
}
else if (sender.tag == 20) {
let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(self.longTap(_:)))
longPressGesture.minimumPressDuration = 2
sender.addGestureRecognizer(longPressGesture)
}

You can check in your #IBAction for the tag you given in storyboard or programmatically, Please check the below code.
#IBAction func action(_ sender: UIButton) {
if sender.tag == 22 { // check for your desired tag instead of "22"
// add longpress gesture. on sender // sender represents your button.
let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(self.handleLongPressGesture(_:)))
longPressGesture.minimumPressDuration = 2 // mention minimum press duration you want user to press.
sender.addGestureRecognizer(longPressGesture)
} else {
}
}

Related

detect when button is pressed down and then up Swift macOS

I'm writing an app that send commands to a set top box.
The box can receive two types of commands: push and release.
I can get the button pressed on macOs in swift.
#IBAction func btnPressed(sender: NSButton) { } in which i send the command and the release. For any command such as change channel, mute or other, all works fine.
Instead, for volume up or done, I need, by doing what I do, to click several time to have the volume up or down.
I got the mouse up and down working, detecting where the click happened (inside the NSImageView (if not a button) corresponding to the up and down images) to simulate a long volume up or down press, but I can't get it inside the button pressed method.
is there a way in the 'buttonpressed' method to combine the mouse event in order to simulate a long press while holding the mouse down?
PS: I have googled and searched here also but did not find a hint.
if it can help:
1 subclass the button class to fire the action on mouseDown and mouseUp (the action will be fired twice)
class myButton: NSButton {
override func awakeFromNib() {
super.awakeFromNib()
let maskUp = NSEvent.EventTypeMask.leftMouseUp.rawValue
let maskDown = NSEvent.EventTypeMask.leftMouseDown.rawValue
let mask = Int( maskUp | maskDown ) // cast from UInt
//shortest way for the above:
//let mask = NSEvent.EventTypeMask(arrayLiteral: [.leftMouseUp, .leftMouseDown]).rawValue
self.sendAction(on: NSEvent.EventTypeMask(rawValue: NSEvent.EventTypeMask.RawValue(mask)))
//objC gives: [self.button sendActionOn: NSLeftMouseDownMask | NSLeftMouseUpMask];
}
}
2: in the storyboard, change the class of the NSButton to your class:
3: set the sender of the action to your subclass and check the currentEvent type:
#IBAction func volUpPressed(sender: myButton) {
let currEvent = NSApp.currentEvent
if(currEvent?.type == .leftMouseDown) {
print("volume Up pressed Down")
//... do your stuff here on mouseDown
}
else
if(currEvent?.type == .leftMouseUp) {
print("volume Up pressed Up")
//... do your stuff here on mouseUp
}
}

How to highlight one part of a tableview cell in swift?

I have two clicks of gesture recognizer in my tableview cell to access different storyboards.
My second click is in the extreme right of my cell and I want when I click on it to just highlight that button and not the whole cell which includes the other button
So my question is : how to separate highlights of different clicks in a tableview cell ?
First you need to set the
tableView.allowsSelection = false
You can add two views in the cell and add tap
func setAccessoryViewTapGestures() {
var tapGestureforLeftAccesoryView = UITapGestureRecognizer()
tapGestureforLeftAccesoryView = UITapGestureRecognizer(target: self, action: #selector(leftAccessoryViewTapped(_:)))
tapGestureforLeftAccesoryView.numberOfTapsRequired = 1
tapGestureforLeftAccesoryView.numberOfTouchesRequired = 1
leftAccessoryView.addGestureRecognizer(tapGestureforLeftAccesoryView)
leftAccessoryView.isUserInteractionEnabled = true
var tapGestureforRightAccesoryView = UITapGestureRecognizer()
tapGestureforRightAccesoryView = UITapGestureRecognizer(target: self, action: #selector(rightAccessoryViewTapped(_:)))
tapGestureforRightAccesoryView.numberOfTapsRequired = 1
tapGestureforRightAccesoryView.numberOfTouchesRequired = 1
rightAccessoryView.addGestureRecognizer(tapGestureforRightAccesoryView)
rightAccessoryView.isUserInteractionEnabled = true
}
Here rightAccessoryView and leftAccessoryView are the view in the cell
#objc private func leftAccessoryViewTapped(_ sender: UITapGestureRecognizer) {
// Add code to highlight the view
}
#objc private func rightAccessoryViewTapped(_ sender: UITapGestureRecognizer) {
// Add code to highlight the view
}
I think this helps

How do i add doneaction and change the done text?

I am using IQKeyboardManager and i added custom action for the done button
txtfield.addDoneOnKeyboard(withTarget: self, action: #selector(doneButtonClicked), titleText: "Next")
IQKeyboardManager.shared().toolbarDoneBarButtonItemText = "Next"
#objc func doneButtonClicked(_ sender: Any) {
// do stuff
}
Here the action gets called and everything works. But the title of the donebutton is DONE (in bluecolor).
The "Next" is show at the middle of the keyboard as titletext. How do i change the text/color of the done button? If i dont add any action to any specific textfield, the second line works perfectly , but anytime i add action, the custom name for done button is ignored.
Any help?
IQKeyboardManager in github
Use the following:
let config = IQBarButtonItemConfiguration(title: "Next", action: #selector(doneButtonClicked))
txtfield.addKeyboardToolbar(withTarget: self, titleText: nil , rightBarButtonConfiguration: config, previousBarButtonConfiguration: nil, nextBarButtonConfiguration: nil)
// any color you like
txtfield.keyboardToolbar.doneBarButton.setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.red], for: UIControl.State.normal)
Instead of:
txtfield.addDoneOnKeyboard(withTarget: self, action: #selector(doneButtonClicked), titleText: "Next")
what is more? titleText sets toolbar.titleBarButton.title.
I pick some code snip from IQKeyboardManager source code here:
//Title button
toolbar.titleBarButton.title = titleText
while toolbarDoneBarButtonItemText set's doneBarButton.title
some code snip from IQKeyboardManager here:
if let rightConfig = rightBarButtonConfiguration {
var done = toolbar.doneBarButton
if rightConfig.barButtonSystemItem == nil && done.isSystemItem == false {
done.title = rightConfig.title
done.image = rightConfig.image
done.target = target
done.action = rightConfig.action
}
Try this one.
import IQKeyboardManagerSwift
IQKeyboardManager.shared.toolbarDoneBarButtonItemText = "NEXT"
See below picture has the NEXT button in Xcode 10.1.

Swift - LongPress Gesture on Button to record Audio with AVFoundation

I'm trying to implement a record button for my chat, which records as long as you hold the button. I implemented a longpressGestureRecognizer, but unfortunately it only records for one second, no matter how long I press.
Here is the code:
let longPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(longPress(_:)))
longPressGestureRecognizer.minimumPressDuration = 1
self.recordingSession = AVAudioSession.sharedInstance()
do {
try self.recordingSession.setCategory(AVAudioSessionCategoryPlayAndRecord)
try self.recordingSession.setActive(true)
self.recordingSession.requestRecordPermission() { [unowned self] allowed in
DispatchQueue.main.async {
if allowed {
self.record_button.addGestureRecognizer(longPressGestureRecognizer)
} else {
// failed to record!
}
}
}
} catch {
// failed to record!
}
// Gesture Recognizer for the Record Button, so as long as it is pressed, record!
func longPress(_ longPressGestureRecognizer: UILongPressGestureRecognizer){
if longPressGestureRecognizer.state == .ended {
print("long press ended")
let recordImage = UIImage(named: "ic_mic_white")
record_button.setImage(recordImage, for: .normal)
self.recordTapRelease()
}
if longPressGestureRecognizer.state == .began {
let recordingTapImage = UIImage(named: "ic_mic_none_white")
record_button.setImage(recordingTapImage, for: .normal)
self.recording()
}
}
EDIT
I implemented the .touchdown .touchupinside events etc.
I still get the same behaviour, unless I slight up above the record button leaving the orange view. Then the recording image button image also changes, showing recording, and if I release and move further up it stops recording.
You don't even have to create UILongPressGestureRecognizer for achieving this; You can do it by implementing touchDown, touchUpInside and touchDragExit events for a UIButton.
At the first look, it might seems that it's more complicated than working with UILongPressGestureRecognizer, but I think that it is more logical and even more readable.
Follow the steps in this answer and hopefully you will get the desired behavior for your recording button. It also has another answer if you insist to use UILongPressGestureRecognizer.
Hope this helped.

How can I find button tag after implementing gesture recogniser in swift?

I want an action to be done once when someone swipes within a button.
My current code is as follows:
let recogniser = UISwipeGestureRecognizer(target: self, action: "didTapButton2:")
recogniser.direction = .Up
button.addGestureRecognizer(recogniser)
func didTapButton2(sender: UIGestureRecognizer!) {
//Here I want to be able to recognise which button this was sent from (they are all tagged)
let button = sender. as UIButton //Gives an error
I need to use gesture recognisers as opposed to UIControlEvents as I need the event to only fire once. Using this makes the event fire loads of times - just need it to go once:
button.addTarget(self, action: "didTapButton2:", forControlEvents: .TouchDragInside)
Does anyone have a solution? Thanks
A UIGestureRecognizer has a property called view which is the view that it is attached to. View is declared as an optional, so you need to unwrap it:
if let button = sender.view as? UIButton {
// use button
if button.tag == 10 {
// handle button tagged with 10
}
}