Controlling text alpha with tap, and screen brightness with pan gesture - ios

I'm trying to design an interface where a tap fades text in, then fades it out, but dragging two fingers up on the screen makes it brighter, and dragging two fingers down make the screen dimmer. I've gotten the text to fade in and out, but I can't seem to get the brightness functionality to work. The app is building, but the two finger gesture does nothing at all.
I have tried inserting code found here.
I have tried several other methods found on Stack Overflow, such as those found here as well, but with no luck.
UPDATE: I made some changes based off of feedback in the comments from #rmaddy and #leo-dabus. There's still nothing at all happening when I pan in the simulator or on my iPhone. I'm not sure if I should be using "recognizer.state" instead of "sender.state". I'm sure I'm making lots of beginner mistakes. Do I even have the code for the pan gesture in the right place? Here's what I have now:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
// Hide text on launch
self.text.alpha = 0
}
// Introducing: The text!
#IBOutlet weak var text: UITextView!
// Show text upon tap of gesture recognizer
#IBAction func tap(_ sender: UITapGestureRecognizer) {
// fade in
UIView.animate(withDuration: 0.5, animations: {
self.text.alpha = 1.0
}) { (finished) in
// fade out
UIView.animate(withDuration: 4.0, animations: {
self.text.alpha = 0.0
})
}
}
#IBAction func twoFingerPan(_ sender: UIPanGestureRecognizer) {
if sender.state == UIPanGestureRecognizer.State.changed || sender.state == UIPanGestureRecognizer.State.ended {
let velocity:CGPoint = sender.velocity(in: self.view)
if velocity.y > 0 {
UIScreen.main.brightness -= 0.03
}
else {
UIScreen.main.brightness += 0.03
}
}
}
}

I suggest creating a couple of gesture recognizers. Something like this:
fileprivate func setGestureRecognizers() {
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tap(_:)))
tapGesture.delegate = self as? UIGestureRecognizerDelegate
tapGesture.numberOfTapsRequired = 1
view.addGestureRecognizer(tapGesture)
let panGesture = UIPanGestureRecognizer.init(target: self, action: #selector(twoFingerPan(_:)))
panGesture.delegate = self as? UIGestureRecognizerDelegate
panGesture.minimumNumberOfTouches = 1
view.addGestureRecognizer(panGesture)
}
On viewDidLoad call this method:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
// Hide text on launch
self.text.alpha = 0
setGestureRecognizers()
}
Then I change a little your methods because I set the gesture recognizers using code and not storyboards, so I got rid of #IBAction and added #objc. Also I was testing this on my phone and comparing velocity.y > 0 made the gesture too sensitive to finger movement, so I changed it to 0.4 instead.
// Show text upon tap of gesture recognizer
#objc func tap(_ sender: UITapGestureRecognizer) {
// fade in
UIView.animate(withDuration: 0.5, animations: {
self.text.alpha = 1.0
}) { (finished) in
// fade out
UIView.animate(withDuration: 4.0, animations: {
self.text.alpha = 0.0
})
}
}
#objc func twoFingerPan(_ sender: UIPanGestureRecognizer) {
if sender.state == UIPanGestureRecognizer.State.changed || sender.state == UIPanGestureRecognizer.State.ended {
let velocity:CGPoint = sender.velocity(in: self.view)
if velocity.y > 0.4 {
UIScreen.main.brightness -= CGFloat(0.03)
}
else {
UIScreen.main.brightness += CGFloat(0.03)
}
}
}

Related

How to hide a view's subviews (Floating Action button) from tapping two different areas

I created a floating action button which i would like to dismiss all the action button when a user either taps the FAB when it's open or when the user taps anywhere on the screen and FAB is open. It is also important to note that the FAB is being displayed over a tableview and i want to retain the ability to select tableview cells.
In my implementation of the FAB i added a target to the FAB button which i use to open and close the FAB and i also implemented a tapGesture on the viewController with the tableview such that when a tap gesture is invoked i can close the FAB if open.
To make this work i did a bit of research and found out that i have to set
tap.cancelsTouchesInView = false
so that the tableView events continue working. However the side effect is that when i tap on the fab to close it two events are fired one from the tapGesture of the FAB and another from the button target which results in the FAB not closing when u tap on it if its open.
Is there a more elegant way of making the FAB be able to close when tapped whilst its open and also have the tap Gesture on the viewController close the fab when its open and a user taps anywhere on the screen.
Here is some of my code:
ViewController:
override func viewDidLoad() {
super.viewDidLoad()
let tap = UITapGestureRecognizer(target: self,
action: #selector(self.dismissActionButtons(_:)))
self.view.addGestureRecognizer(tap)
tap.cancelsTouchesInView = false
self.floatingActionButton.isHidden = true
}
#objc func dismissActionButtons(_ sender: UIButton) {
if !floatingActionButton.actionButtonsCarousel.isHidden {
self.floatingActionButton.animateActionButtonsDisappering()
}
}
Custom FAB View :
override init(frame: CGRect) {
super.init(frame: .zero)
actionButtonsCarousel.isHidden = true
self.translatesAutoresizingMaskIntoConstraints = false
self.mainButton.addTarget(self,
action: #selector(ACTFAB.fabButtonAction(_:)),
for: .touchUpInside)
}
#objc func fabButtonAction(_ sender: UIButton) {
if self.actionButtonsCarousel.isHidden {
self.animateActionButtonsAppering()
} else {
self.animateActionButtonsDisappering()
}
}
func animateActionButtonsAppering() {
self.actionButtonsCarousel.alpha = 0.0
self.actionButtonsCarousel.isHidden = false
UIView.transition(with: self, duration: 0.5, options: .preferredFramesPerSecond60, animations: {
self.actionButtonsCarousel.alpha = 1.0
})
self.mainButton.setImage(UIImage(named: "fab-open-icon"), for: .normal)
}
func animateActionButtonsDisappering() {
self.actionButtonsCarousel.alpha = 1.0
self.actionButtonsCarousel.isHidden = true
UIView.transition(with: self, duration: 0.3, options: .transitionCrossDissolve, animations: {
self.actionButtonsCarousel.alpha = 0.0
})
self.mainButton.setImage(UIImage(named: "fab-closed-icon"), for: .normal)
}
Two valid scenarios:
1 FAB is open -> click FAB -> FAB closes
2 FAB is open -> click anywhere other than FAB -> FAB closes
Scenario number 1 fails with my current code.
If I understand your question correctly, the issue is that tapping the FAB causes both the button's action to be fired but also, as you are passing the event through to the underlying viewController, the gestureRecogniser to fire too.
I'm assuming the button action is the primary event, and that when this fires you need to stop the gestureRecogniser. A gestureRecogniser has a .location(in:) method which allows you to get the first tap location (for a tapGestureRecogniser) in terms of any view, and a UIView has a .point(inside: with:) method that checks whether a CGPoint (in terms of its own coordinate space) is inside it bounds. Therefore you should be able to do something like this (from memory and not compiled, so may need some tweaking but hopefully it should get you started):
#objc func dismissActionButtons(_ sender: UIButton) {
let tapPoint = sender.location(in: customFABview)
if customFABview.point(inside: tapPoint, with: nil) &&
!floatingActionButton.actionButtonsCarousel.isHidden {
self.floatingActionButton.animateActionButtonsDisappering()
}
}
Continuing with #flanker's answer i created a boolean in the fab to check if the event was coming from tapGesture then i added it to the check conditional statement as follows:
var isComingFromGestureEvent: Bool = false
#objc func fabButtonAction(_ sender: UIButton) {
if self.actionButtonsCarousel.isHidden && !isComingFromGestureEvent {
self.animateActionButtonsAppering()
} else {
self.animateActionButtonsDisappering()
}
}
In the ViewController i then just used flanker's answer to set the boolean state as follows :
var locationInView: CGPoint = CGPoint(x: 0, y: 0)
override func viewDidLoad() {
super.viewDidLoad()
let tap = UITapGestureRecognizer(target: self,
action: #selector(self.dismissActionButtons(_:)))
self.view.addGestureRecognizer(tap)
pointInView = tap.location(in: floatingActionButton)
tap.cancelsTouchesInView = false
self.floatingActionButton.isHidden = true
}
#objc func dismissActionButtons(_ sender: UIButton) {
let tapPoint = pointInView
if floatingActionButton.point(inside: tapPoint, with: nil) &&
!floatingActionButton.actionButtonsCarousel.isHidden {
self.floatingActionButton.isComingFromGestureEvent = true
self.floatingActionButton.animateActionButtonsDisappering()
} else {
self.floatingActionButton.isComingFromGestureEvent = false
}
}

Gesture recogniser not working when other view is on top of the google maps

I am trying to add swipe gesture recognizer for a sidebar. I have created a side bar which is working fine and I can open/close it using a bar button. View is sliding out of left side and is placed on top of the google maps view.
It would be only logical if user would be able to sfipe to the left to close side bar, but unfortunately it is not working.
#IBOutlet weak var sideMenuView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
mapView.isMyLocationEnabled = true
mapView.delegate = self
self.locationManager.delegate = self
self.locationManager.startUpdatingLocation()
setUpSideMenuWidth()
let swipeLeft = UISwipeGestureRecognizer(target: self, action: #selector(swipeAction))
swipeLeft.direction = .left
self.sideMenuView.addGestureRecognizer(swipeLeft)
}
func setUpSideMenuWidth() {
self.mapView.bringSubviewToFront(self.sideMenuView)
sideMenuWidth = screenSize.width * 0.7
self.widthSideMenuConstraint.constant = sideMenuWidth
self.leadingConstraint.constant = -sideMenuWidth
self.sideMenuView.layoutIfNeeded()
}
#objc func swipeAction(swipe: UISwipeGestureRecognizer) {
menuViewAction()
}
func menuViewAction() {
if (menuShowing) {
self.leadingConstraint.constant = -sideMenuWidth
UIView.animate(withDuration: 0.3, animations: {
self.view.layoutIfNeeded()
})
} else {
self.leadingConstraint.constant = 0
UIView.animate(withDuration: 0.3, animations: {
self.view.layoutIfNeeded()
})
}
menuShowing = !menuShowing
}
I somehow feel that it is related that my side menu is a subview of mapsView. Have everyone faced such problem because when I use simply a bar button it opens and closes perfectly but swipe is not working by some kind of reason. I have also tried to add gesture view storyboard but without luck.

fade in button so it won't automatically fade out again

I'm using a tap gesture recogniser so if the user taps on the screen the button fades out for 5 seconds and then if the user wants to see the buttons on the screen again they tap on the screen and the button fades in.
The Problem is:
I can't disable the button when it fades in so it won't automatically fade out again. I tried to invalidate the timer but that didn't work. To be more specific of what I want to do:
On app load, you see an enabled "Start Stop Button." - Tap anywhere on the screen and a 5 second timer starts to fade the button out and disables it. Once the button fades out and disables, I can tap anywhere on the screen to fade the button back in, enable it, and kill the timer so the button shows up as it was before I first tapped it.
class ViewController: UIViewController {
// Create these 3 properties in the top of your class
var secondToFadeOut = 5 // How many second do you want the view to idle before the button fades. You can change this to whatever you'd like.
var timer = Timer() // Create the timer!
var isTimerRunning: Bool = false // Need this to prevent multiple timers from running at the same time.
#IBOutlet weak var startStopButton: UIButton! // The outlet for your button. This is used to fade it in and out, and enable / disable it.
override func viewDidLoad() {
super.viewDidLoad()
startStopButton.isEnabled = true
runTimer()
// Add a tap gesture recognizer to the main view to determine when the screen was tapped (for the purpose of resetting the timer).
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.tap(_:)))
self.view.addGestureRecognizer(tapRecognizer)
}
func runTimer() {
// Create the timer to run a method (in this case... updateTimer) every 1 second.
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(ViewController.updateTimer)), userInfo: nil, repeats: true)
// Set the isTimerRunning bool to true
isTimerRunning = true
}
#objc func updateTimer() {
// Every 1 second that this method runs, 1 second will be chopped off the secondToFadeOut property. If that hits 0 (< 1), then run the fadeOutButton and invalidate the timer so it stops running.
secondToFadeOut -= 1
print(secondToFadeOut)
if secondToFadeOut < 1 {
fadeOutButton()
timer.invalidate()
isTimerRunning = false
}
}
#objc func tap(_ gestureRecognizer: UITapGestureRecognizer) {
// When the view is tapped (based on the gesture recognizer), reset the secondToFadeOut property, fade in (and enable) the button.
//secondToFadeOut = 5
fadeInButton()
timer.invalidate()
//if isTimerRunning == false {
// runTimer()
//}
}
func fadeOutButton() {
// Fade out your button! I also disabled it here. But you can do whatever your little heart desires.
UIView.animate(withDuration: 0.5) {
self.startStopButton.alpha = 0.25
}
self.startStopButton.isEnabled = false
}
func fadeInButton() {
// Fade the button back in, and set it back to active (so it's tappable)
UIView.animate(withDuration: 0.5) {
self.startStopButton.alpha = 1
}
self.startStopButton.isEnabled = true
}
#IBAction func startStopButtonPressed(_ sender: UIButton) {
print("Start Stop Button Pressed")
}
}
My best guess is that you have a rogue Timer object that remains in memory even after you invalidate your current timer, and that is causing the button to fade out again after it fades in.
I have made several edits to your class. Check the code out:
class ViewController: UIViewController {
// Create these 3 properties in the top of your class
var secondToFadeOut = 5 // How many second do you want the view to idle before the button fades. You can change this to whatever you'd like.
var timer? = nil // Create the timer!
#IBOutlet weak var startStopButton: UIButton! // The outlet for your button. This is used to fade it in and out, and enable / disable it.
override func viewDidLoad() {
super.viewDidLoad()
startStopButton.isEnabled = true
runTimer()
// Add a tap gesture recognizer to the main view to determine when the screen was tapped (for the purpose of resetting the timer).
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.tap(_:)))
self.view.addGestureRecognizer(tapRecognizer)
}
func runTimer() {
if timer == nil {
timer = Timer.scheduledTimer(timeInterval: secondToFadeOut, target: self, selector: (#selector(ViewController.timerFired)), userInfo: nil, repeats: false)
}
}
#objc func timerFired() {
timer = nil
if self.startStopButton.isEnabled {
fadeOutButton()
} else {
fadeInButton()
}
}
#objc func tap(_ gestureRecognizer: UITapGestureRecognizer) {
runTimer()
}
func fadeOutButton() {
UIView.animate(withDuration: 0.5) {
self.startStopButton.alpha = 0.25
}
self.startStopButton.isEnabled = false
}
func fadeInButton() {
UIView.animate(withDuration: 0.5) {
self.startStopButton.alpha = 1
}
self.startStopButton.isEnabled = true
}
#IBAction func startStopButtonPressed(_ sender: UIButton) {
print("Start Stop Button Pressed")
}
}

Imiplenting panGesture on a viewController [duplicate]

Right now I have a scrollView that takes up the entire view controller. The code below is able to move the scrollView around but I want to move the whole view controller around. How would I do that?
override func viewDidLoad() {
pan = UIPanGestureRecognizer(target: self, action: "handlePan:")
self.scrollview.addGestureRecognizer(pan)
}
func handlePan(recognizer:UIPanGestureRecognizer!) {
switch recognizer.state {
case .Changed:
handlePanChanged(recognizer); break
case .Ended:
handlePanTerminated(recognizer); break
case .Cancelled:
handlePanTerminated(recognizer); break
case .Failed:
handlePanTerminated(recognizer); break
default: break
}
}
func handlePanChanged(recognizer:UIPanGestureRecognizer!) {
if let view = recognizer.view {
var translation = recognizer.translationInView(self.view)
println("moving")
view.center = CGPointMake(view.center.x, view.center.y + translation.y);
recognizer.setTranslation(CGPointZero, inView: self.view)
}
}
I've tried different variations of "self.view.center ...." "UIApplication.sharedApplication.rootViewController.view.center.." etc.
I infer from your other question that you want to a gesture to dismiss this view controller. Rather than manipulating the view yourself in the gesture, I'd suggest you use custom transition with a UIPercentDrivenInteractiveTransition interaction controller, and have the gesture just manipulate the interaction controller. This achieves the same UX, but in a manner consistent with Apple's custom transitions paradigm.
The interesting question here is how do you want to delineate between the custom dismiss transition gesture and the scroll view gesture. What you want is some gesture that is constrained in some fashion. There are tons of options here:
If the scroll view is left-right only, have a custom pan gesture subclass that fails if you use it horizontally;
If the scroll view is up-down, too, then have a top "screen edge gesture recognizer" or add some visual element that is a "grab bar" to which you tie a pan gesture
But however you design this gesture to work, have the scroll view's gestures require that your own gesture fails before they trigger.
For example, if you wanted a screen edge gesture recognizer, that would look like:
class SecondViewController: UIViewController, UIViewControllerTransitioningDelegate {
#IBOutlet weak var scrollView: UIScrollView!
var interactionController: UIPercentDrivenInteractiveTransition?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
modalPresentationStyle = .Custom
transitioningDelegate = self
}
override func viewDidLoad() {
super.viewDidLoad()
// ...
let edge = UIScreenEdgePanGestureRecognizer(target: self, action: "handleScreenEdgeGesture:")
edge.edges = UIRectEdge.Top
view.addGestureRecognizer(edge)
for gesture in scrollView.gestureRecognizers! {
gesture.requireGestureRecognizerToFail(edge)
}
}
// because we're using top edge gesture, hide status bar
override func prefersStatusBarHidden() -> Bool {
return true
}
func handleScreenEdgeGesture(gesture: UIScreenEdgePanGestureRecognizer) {
switch gesture.state {
case .Began:
interactionController = UIPercentDrivenInteractiveTransition()
dismissViewControllerAnimated(true, completion: nil)
case .Changed:
let percent = gesture.translationInView(gesture.view).y / gesture.view!.frame.size.height
interactionController?.updateInteractiveTransition(percent)
case .Cancelled:
fallthrough
case .Ended:
if gesture.velocityInView(gesture.view).y < 0 || gesture.state == .Cancelled || (gesture.velocityInView(gesture.view).y == 0 && gesture.translationInView(gesture.view).y < view.frame.size.height / 2.0) {
interactionController?.cancelInteractiveTransition()
} else {
interactionController?.finishInteractiveTransition()
}
interactionController = nil
default: ()
}
}
#IBAction func didTapDismissButton(sender: UIButton) {
dismissViewControllerAnimated(true, completion: nil)
}
// MARK: UIViewControllerTransitioningDelegate
func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return DismissAnimation()
}
func interactionControllerForDismissal(animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
return interactionController
}
}
class DismissAnimation: NSObject, UIViewControllerAnimatedTransitioning {
func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
return 0.25
}
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
let from = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!
let container = transitionContext.containerView()!
let height = container.bounds.size.height
UIView.animateWithDuration(transitionDuration(transitionContext), animations:
{
from.view.transform = CGAffineTransformMakeTranslation(0, height)
}, completion: { finished in
transitionContext.completeTransition(!transitionContext.transitionWasCancelled())
}
)
}
}
Personally, I find the notion of having top and bottom screen edge gestures to be a bad UX, so I'd personally change this modal presentation to slide in from the right, and then swiping from left edge to the right feels logical, and doesn't interfere with the built in top pull down (for iOS notifications). Or if the scroll view only scrolls horizontally, then you can just have your own vertical pan gesture that fails if it's not a vertical pan.
Or, if the scroll view only scrolls left and right, you can add your own pan gesture that is only recognized when you pull down by (a) using UIGestureRecognizerDelegate to recognize downward pans only; and (b) again setting the scroll view gestures to only recognize gestures if our pull-down gesture fails:
override func viewDidLoad() {
super.viewDidLoad()
// ...
let pan = UIPanGestureRecognizer(target: self, action: "handlePan:")
pan.delegate = self
view.addGestureRecognizer(pan)
for gesture in scrollView.gestureRecognizers! {
gesture.requireGestureRecognizerToFail(pan)
}
}
func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool {
if let gesture = gestureRecognizer as? UIPanGestureRecognizer {
let translation = gesture.translationInView(gesture.view)
let angle = atan2(translation.x, translation.y)
return abs(angle) < CGFloat(M_PI_4 / 2.0)
}
return true
}
func handlePan(gesture: UIPanGestureRecognizer) {
// the same as the `handleScreenEdgeGesture` above
}
Like I said, tons of options here. But you haven't shared enough of your design for us to advise you further on that.
But the above illustrates the basic idea, that you shouldn't be moving the view around yourself, but rather use custom transition with your own animators and your own interactive controller.
For more information, see WWDC 2013 Custom Transitions Using View Controllers (and also WWDC 2014 A Look Inside Presentation Controllers, if you want a little more information on the evolution of custom transitions).

Swift: Long Press Gesture Recognizer - Detect taps and Long Press

I want to wire an action such that if the gesture is a tap, it does animates an object in a particular way but if the press duration was more than .5 secs it does something else.
Right now, I just have the animation hooked up. I don't know how I can differentiate between a long press and a tap?
How do I access the press duration to achieve the above?
#IBAction func tapOrHold(sender: AnyObject) {
UIView.animateKeyframesWithDuration(duration, delay: delay, options: options, animations: {
UIView.addKeyframeWithRelativeStartTime(0, relativeDuration: 0, animations: {
self.polyRotate.transform = CGAffineTransformMakeRotation(1/3 * CGFloat(M_PI * 2))
})
UIView.addKeyframeWithRelativeStartTime(0, relativeDuration: 0, animations: {
self.polyRotate.transform = CGAffineTransformMakeRotation(2/3 * CGFloat(M_PI * 2))
})
UIView.addKeyframeWithRelativeStartTime(0, relativeDuration: 0, animations: {
self.polyRotate.transform = CGAffineTransformMakeRotation(3/3 * CGFloat(M_PI * 2))
})
}, completion: { (Bool) in
let vc : AnyObject! = self.storyboard?.instantiateViewControllerWithIdentifier("NextView")
self.showViewController(vc as UIViewController, sender: vc)
})
Define two IBActions and set one Gesture Recognizer to each of them. This way you can perform two different actions for each gesture.
You can set each Gesture Recognizer to different IBActions in the interface builder.
#IBAction func tapped(sender: UITapGestureRecognizer)
{
println("tapped")
//Your animation code.
}
#IBAction func longPressed(sender: UILongPressGestureRecognizer)
{
println("longpressed")
//Different code
}
Through code without interface builder
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: "tapped:")
self.view.addGestureRecognizer(tapGestureRecognizer)
let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: "longPressed:")
self.view.addGestureRecognizer(longPressRecognizer)
func tapped(sender: UITapGestureRecognizer)
{
println("tapped")
}
func longPressed(sender: UILongPressGestureRecognizer)
{
println("longpressed")
}
Swift 5
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapped))
self.view.addGestureRecognizer(tapGestureRecognizer)
let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(longPressed))
self.view.addGestureRecognizer(longPressRecognizer)
#objc func tapped(sender: UITapGestureRecognizer){
print("tapped")
}
#objc func longPressed(sender: UILongPressGestureRecognizer) {
print("longpressed")
}
For swift2
let lpgr = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress))
lpgr.minimumPressDuration = 0.5
lpgr.delaysTouchesBegan = true
lpgr.delegate = self
self.featuredCouponColView.addGestureRecognizer(lpgr)
Action
//MARK: - UILongPressGestureRecognizer Action -
func handleLongPress(gestureReconizer: UILongPressGestureRecognizer) {
if gestureReconizer.state != UIGestureRecognizerState.Ended {
//When lognpress is start or running
}
else {
//When lognpress is finish
}
}
For Swift 4.2/ Swift 5
let lpgr = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress))
lpgr.minimumPressDuration = 0.5
lpgr.delaysTouchesBegan = true
lpgr.delegate = self
self.colVw.addGestureRecognizer(lpgr)
//MARK: - UILongPressGestureRecognizer Action -
#objc func handleLongPress(gestureReconizer: UILongPressGestureRecognizer) {
if gestureReconizer.state != UIGestureRecognizer.State.ended {
//When lognpress is start or running
}
else {
//When lognpress is finish
}
}
Through code without interface builder
// Global variables declaration
var longPressed = false
var selectedRow = 0
override func viewDidLoad() {
super.viewDidLoad()
let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(ContactListTableViewController.handleLongPress(_:)))
longPressGesture.minimumPressDuration = 1.0 // 1 second press
longPressGesture.allowableMovement = 15 // 15 points
longPressGesture.delegate = self
self.tableView.addGestureRecognizer(longPressGesture)
}
// Long tap work goes here !!
if (longPressed == true) {
if(tableView.cellForRowAtIndexPath(indexPath)?.accessoryType == .Checkmark){
tableView.cellForRowAtIndexPath(indexPath)?.accessoryType = .None
self.selectedRow -= 1
if(self.selectedRow == 0){
self.longPressed = false
}
} else {
self.selectedRow += 1
tableView.cellForRowAtIndexPath(indexPath)?.accessoryType = .Checkmark
}
} else if(self.selectedRow == 0) {
// Single tape work goes here !!
}
But the only problem is the long press gesture runs two times. If you have found any solution do comment below !
Swift 5 using interface builder
for the normal tap you can simply create a touch up inside action from your button.
for the long press, create an outlet for your button, create the tap gesture recognizer and set it to the button then create the selector method to perform the long press tasks.
#IBOutlet var myButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(addToListButtonLongPress(_:)))
longPressRecognizer.numberOfTouchesRequired = 1
longPressRecognizer.allowableMovement = 10
longPressRecognizer.minimumPressDuration = 0.5
myButton.addGestureRecognizer(longPressRecognizer)
}
// Connected to myButton in interface builder.
#IBAction func myButtonTapped(_ sender: UIButton) {
print("button tapped")
}
#objc func myButtonLongPressed(_ sender: UILongPressGestureRecognizer) {
print("button long pressed")
}

Resources