Receive user input from UISwipeGestureRecognizer and UIScrollView - ios

I am trying to create a UIScrollView that performs an action on scrollViewWillBeginDragging and also recognizes left and right swipes using UISwipeGestureRecognizer. When I use the scrollViewWillBeginDragging function, I get the desired result on a left swipe but my function cannot tell whether I am performing a right or left swipe. If I set detailScrollView.userInteractionEnabled = false, the gestureRecognizer performs correctly but the view no longer scrolls. Here is my code:
override func viewDidLoad() {
super.viewDidLoad()
var leftSwipe = UISwipeGestureRecognizer(target: self, action: Selector("handleSwipes:"))
var rightSwipe = UISwipeGestureRecognizer(target: self, action: Selector("handleSwipes:"))
leftSwipe.direction = .Left
rightSwipe.direction = .Right
view.addGestureRecognizer(leftSwipe)
view.addGestureRecognizer(rightSwipe) }
func gestureRecognizer(UIGestureRecognizer,
shouldRecognizeSimultaneouslyWithGestureRecognizer:UIGestureRecognizer) -> Bool {
return true
}
func scrollViewWillBeginDragging(scrollView: UIScrollView) {
if (counter < buttons.count) {
serialSelected(buttons[counter])
counter += 1
}
}
func handleSwipes(sender:UISwipeGestureRecognizer) {
if (sender.direction == .Left) {
println("Swipe Left")
var labelPosition = CGPointMake(self.contentView.frame.origin.x - 50.0, self.contentView.frame.origin.y);
contentView.frame = CGRectMake( labelPosition.x , labelPosition.y , self.contentView.frame.size.width, self.contentView.frame.size.height)
}
if (sender.direction == .Right) {
println("Swipe Right")
var labelPosition = CGPointMake(self.contentView.frame.origin.x + 50.0, self.contentView.frame.origin.y);
contentView.frame = CGRectMake( labelPosition.x , labelPosition.y , self.contentView.frame.size.width, self.contentView.frame.size.height)
}
}

According to your source code, the shouldRecognizeSimultaneouslyWithGestureRecognizer:UIGestureRecognizer is never invoked.
// Make yourself a delegate
class yourClass: parentClass, UIGestureRecognizerDelegate
// reference the delegate
leftSwipe.delegate = self
rightSwipe.delegate = self

Related

How to Swipe UIView on Button Action in all four directions

I have Two UIButtons on Right and Left and a UIView At Middle of the button..
I have to swipe ContainerView with some animation on UIButton click..
If user tap on right button ContainerView swipe to .right direction....If user tap on Left button ContainerView swipe to .left direction..
I have not found it anyWhere....Need help with full coding part
I have done this on my view
override func viewDidAppear(_ animated: Bool) {
leftSwipe()
rightSwipe()
}
//MARK:Left Swipe Function
func leftSwipe()
{
let swipeLeft = UISwipeGestureRecognizer()
swipeLeft.direction = .left
self.insideContainerViewSecond.addGestureRecognizer(swipeLeft)
swipeLeft.addTarget(self, action: #selector(swipe(sender:)))
}
//MARK:Right Swipe Function
func rightSwipe()
{
let swipeRight = UISwipeGestureRecognizer()
swipeRight.direction = .right
self.insideContainerViewSecond.addGestureRecognizer(swipeRight)
swipeRight.addTarget(self, action: #selector(swipe(sender:)))
}
//MARK: Swipe Function
#objc func swipe(sender: UISwipeGestureRecognizer)
{
switch sender.direction
{
case .left:
print("swiped left")
case .right:
print("swiped right")
default:
print("no action")
}
}
In this image I have a UIView and two button right and left..When I swipe on my UIView It swipe Left and right without animation.....But I need to swipe my UIView on right or Left button action with flip animation
We have CATransition Classes with iOS. You should use this. Or you should constraint animation. Maybe this repo is helped you for first trick.
https://github.com/barankaraoguzzz/FastOnBoarding/blob/master/FOView/Classes/FOAnimation.swift
if this answer doesn't be true for this question. Come again :)
You have a couple different questions...
How to "simulate" a swipe-gesture on a button tap?
You could do this different ways, such as creating a showNextImage() function, and then call it on swipe-left or on right-button-tap.
Or, you could do something like this, where you create a temporary swipe gesture recognizer and pass it to your recognizer function:
#objc func leftButtonTap(_ sender: UIButton)
{
// create a right-swipe-gesture
let sgr = UISwipeGestureRecognizer()
sgr.direction = .right
self.swipe(sender: sgr)
}
#objc func rightButtonTap(_ sender: UIButton)
{
// create a left-swipe-gesture
let sgr = UISwipeGestureRecognizer()
sgr.direction = .left
self.swipe(sender: sgr)
}
You said on swipe (or button tap), you want to use flip animation to show the next (or previous) image?
You can do this by adding two image views to your "container" view. Set one view hidden. When you want to "show the next image," set the .image property of the hidden imageView and then use UIView.transition(...) to flip from the visible imageView to the hidden imageView:
private func flipMe(_ direction: UIView.AnimationOptions) -> Void {
// fromView is the one that is NOT hidden
let fromView = imgViewB.isHidden ? imgViewA : imgViewB
// toView is the one that IS hidden
let toView = imgViewB.isHidden ? imgViewB : imgViewA
UIView.transition(from: fromView,
to: toView,
duration: 0.5,
options: [direction, .showHideTransitionViews],
completion: { b in
// if we want to do something on completion
})
}
Here is a simple example that you can run and see what happens. No #IBOutlet or #IBAction connections, so you don't need any Storyboard setup:
FlipView custom view subclass:
class FlipView: UIView {
// set image names from controller
var imageNames: [String] = [] {
didSet {
if let img = UIImage(named: imageNames[0]) {
imgViewB.image = img
} else {
imgViewB.image = testImage()
}
}
}
// index counter
private var idx: Int = 0
// two image views
private let imgViewA: UIImageView = UIImageView()
private let imgViewB: UIImageView = UIImageView()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() -> Void {
// add both image views
// with light-gray backgrounds
// constraining all 4 sides to self
[imgViewA, imgViewB].forEach { v in
v.backgroundColor = UIColor(white: 0.9, alpha: 1.0)
addSubview(v)
v.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
v.topAnchor.constraint(equalTo: topAnchor),
v.leadingAnchor.constraint(equalTo: leadingAnchor),
v.trailingAnchor.constraint(equalTo: trailingAnchor),
v.bottomAnchor.constraint(equalTo: bottomAnchor),
])
}
// start with one of the image views hidden
imgViewA.isHidden = true
}
private func flipMe(_ direction: UIView.AnimationOptions) -> Void {
// fromView is the one that is NOT hidden
let fromView = imgViewB.isHidden ? imgViewA : imgViewB
// toView is the one that IS hidden
let toView = imgViewB.isHidden ? imgViewB : imgViewA
UIView.transition(from: fromView,
to: toView,
duration: 0.5,
options: [direction, .showHideTransitionViews],
completion: { b in
// if we want to do something on completion
})
}
func flipToPrevious() -> Void {
// don't try to flip past the first image
if idx == 0 {
return
}
// decrement the index
idx -= 1
let hiddenImageView = imgViewA.isHidden ? imgViewA : imgViewB
// get the previous image
if let img = UIImage(named: imageNames[idx]) {
hiddenImageView.image = img
} else {
hiddenImageView.image = testImage()
}
// flip it from left
flipMe(.transitionFlipFromLeft)
}
func flipToNext() -> Void {
// don't try to flip past the last image
if idx == imageNames.count - 1 {
return
}
// increment the index
idx += 1
let hiddenImageView = imgViewA.isHidden ? imgViewA : imgViewB
// get the next image
if let img = UIImage(named: imageNames[idx]) {
hiddenImageView.image = img
} else {
hiddenImageView.image = testImage()
}
// flip it from right
flipMe(.transitionFlipFromRight)
}
// get a numbered system image if the named image
// cannot be loaded from assets
private func testImage() -> UIImage {
let colors: [UIColor] = [
.systemRed, .systemGreen, .systemBlue,
.systemYellow, .systemTeal, .systemPurple,
]
guard let img = UIImage(systemName: "\(idx+1).circle") else {
// that should not fail, but in case it does
return UIImage()
}
return img.withTintColor(colors[idx % colors.count], renderingMode: .alwaysOriginal)
}
}
ViewController example ViewController class:
class ViewController: UIViewController {
let insideContainerViewSecond: FlipView = FlipView()
override func viewDidLoad() {
super.viewDidLoad()
// respect safe area
let g = view.safeAreaLayoutGuide
// create left and right buttons
let leftButton = UIButton()
leftButton.translatesAutoresizingMaskIntoConstraints = false
let leftImg = UIImage(systemName: "chevron.left.circle.fill")
leftButton.setImage(leftImg, for: [])
leftButton.addTarget(self, action: #selector(leftButtonTap(_:)), for: .touchUpInside)
let rightButton = UIButton()
rightButton.translatesAutoresizingMaskIntoConstraints = false
let rightImg = UIImage(systemName: "chevron.right.circle.fill")
rightButton.setImage(rightImg, for: [])
rightButton.addTarget(self, action: #selector(rightButtonTap(_:)), for: .touchUpInside)
insideContainerViewSecond.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(insideContainerViewSecond)
view.addSubview(leftButton)
view.addSubview(rightButton)
NSLayoutConstraint.activate([
insideContainerViewSecond.topAnchor.constraint(equalTo: g.topAnchor, constant: 80.0),
insideContainerViewSecond.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 80.0),
insideContainerViewSecond.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -80.0),
insideContainerViewSecond.heightAnchor.constraint(equalTo: insideContainerViewSecond.widthAnchor, multiplier: 0.5),
leftButton.centerYAnchor.constraint(equalTo: insideContainerViewSecond.topAnchor),
leftButton.centerXAnchor.constraint(equalTo: insideContainerViewSecond.leadingAnchor),
rightButton.centerYAnchor.constraint(equalTo: insideContainerViewSecond.topAnchor),
rightButton.centerXAnchor.constraint(equalTo: insideContainerViewSecond.trailingAnchor),
])
// your array of image names
let imageNames: [String] = [
"pic1", "pic2", "pic3", "pic4", "pic5", "pic6",
]
insideContainerViewSecond.imageNames = imageNames
leftSwipe()
rightSwipe()
}
//MARK:Left Swipe Function
func leftSwipe()
{
let swipeLeft = UISwipeGestureRecognizer()
swipeLeft.direction = .left
self.insideContainerViewSecond.addGestureRecognizer(swipeLeft)
swipeLeft.addTarget(self, action: #selector(swipe(sender:)))
}
//MARK:Right Swipe Function
func rightSwipe()
{
let swipeRight = UISwipeGestureRecognizer()
swipeRight.direction = .right
self.insideContainerViewSecond.addGestureRecognizer(swipeRight)
swipeRight.addTarget(self, action: #selector(swipe(sender:)))
}
//MARK: Swipe Function
#objc func swipe(sender: UISwipeGestureRecognizer)
{
switch sender.direction
{
case .left:
print("swiped left")
self.insideContainerViewSecond.flipToNext()
case .right:
print("swiped right")
self.insideContainerViewSecond.flipToPrevious()
default:
print("no action")
}
}
#objc func leftButtonTap(_ sender: UIButton)
{
// create a right-swipe-gesture
let sgr = UISwipeGestureRecognizer()
sgr.direction = .right
self.swipe(sender: sgr)
}
#objc func rightButtonTap(_ sender: UIButton)
{
// create a left-swipe-gesture
let sgr = UISwipeGestureRecognizer()
sgr.direction = .left
self.swipe(sender: sgr)
}
}

Control Center view

Am trying to create a view like control centre in iPhone. As per my requirement the view have to be at bottom when user swap up, View need to be present from bottom to top, while dismissing view need to be swap bottom.Exactly like control centre I need a view, Can Anyone help me?
You can achieve that by the following code:
class ViewController: UIViewController, UIGestureRecognizerDelegate {
var viewControlCenter : UIView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
createControlCenterView()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Gesture Methods
#objc func respondToSwipeGesture(sender: UIGestureRecognizer? = nil) {
if let swipeGesture = sender as? UISwipeGestureRecognizer {
switch swipeGesture.direction {
case UISwipeGestureRecognizerDirection.up:
if self.viewControlCenter.frame.origin.y != 0 {
UIView.animate(withDuration: 0.5, animations: {
self.viewControlCenter.frame.origin.y = 0
}, completion: nil)
}
break
case UISwipeGestureRecognizerDirection.down:
if self.viewControlCenter.frame.origin.y == 0 {
UIView.animate(withDuration: 0.5, animations: {
self.viewControlCenter.frame.origin.y = self.view.frame.size.height
}, completion: nil)
}
break
default:
break
}
}
}
#objc func onViewTapped(sender: UITapGestureRecognizer? = nil) {
if self.viewControlCenter.frame.origin.y == 0 {
UIView.animate(withDuration: 0.5, animations: {
self.viewControlCenter.frame.origin.y = self.view.frame.size.height
}, completion: nil)
}
}
// MARK: - Custom Methods
func createControlCenterView() {
viewControlCenter = UIView.init(frame: self.view.bounds)
self.viewControlCenter.frame.origin.y = self.view.frame.size.height
let viewBG : UIView = UIView.init(frame: self.view.bounds)
viewBG.backgroundColor = UIColor.init(red: 0, green: 0, blue: 0, alpha: 0.6)
viewControlCenter.addSubview(viewBG)
self.view.addSubview(viewControlCenter)
let swipeUp = UISwipeGestureRecognizer(target: self, action: #selector(respondToSwipeGesture(sender:)))
swipeUp.direction = .up
self.view.addGestureRecognizer(swipeUp)
let swipeDown = UISwipeGestureRecognizer(target: self, action: #selector(respondToSwipeGesture(sender:)))
swipeDown.direction = .down
self.view.addGestureRecognizer(swipeDown)
let tap = UITapGestureRecognizer(target: self, action: #selector(onViewTapped(sender:)))
tap.delegate = self
viewControlCenter.addGestureRecognizer(tap)
}
}

How do I make a UIImageView "flickable"?

I have a UIImageView that the user can move around, but I want the user to kind of swipe it or "flick" it in a direction and it will fly off in the direction the user swiped/flicked it.
Here is the code for the UIImageView:
#IBOutlet var imageView: UIImageView!
var location = CGPoint(x: 0, y: 0)
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
var touch : UITouch! = touches.first as! UITouch
location = touch.locationInView(self.view)
imageView.center = location
}
You need to use UIKit Dynamics.
Here is a tutorial:
http://www.raywenderlich.com/71828/uikit-dynamics-tutorial-tossing-views
U can use UISwipeGestureRecognizer to move
Here is a code
#IBOutlet var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
var rightSwipe = UISwipeGestureRecognizer(target: self, action: "HandleSwipeGesture:")
var leftswipe = UISwipeGestureRecognizer(target: self, action: "HandleSwipeGesture:")
rightSwipe.direction = .Right
leftswipe.direction = .Left
imageView.addGestureRecognizer(rightSwipe)
imageView.addGestureRecognizer(leftswipe)
}
func HandleSwipeGesture(sender:UISwipeGestureRecognizer){
if(sender.direction == .Right){
// do other task
}
else{
if(sender.direction == .Left){
// do other task
}
}
}
for swipe you can try it.
varysLeftSwipe=UISwipeGestureRecognizer(target:self,action:Selector("handleSwipes:"))
var ysRightSwipe = UISwipeGestureRecognizer(target: self, action: Selector("handleSwipes:"))
ysLeftSwipe.direction = UISwipeGestureRecognizerDirection.Left
ysRightSwipe.direction = UISwipeGestureRecognizerDirection.Right
ysSlideImageView.addGestureRecognizer(ysLeftSwipe)
ysSlideImageView.addGestureRecognizer(ysRightSwipe)
func handleSwipes(sender:UISwipeGestureRecognizer) {
if (sender.direction == .Left) {
self.showNextData()
}
if (sender.direction == .Right) {
self.showPreviousData()
}
}
func showPreviousData(){
if index > 0 {
index = index - 1
ysForWordButton.hidden = false
if index == 0{
ysBackWordButton.hidden = true
}
}
else{
ysBackWordButton.hidden = true
ysForWordButton.hidden = false
}
ysSlideImageView.image = UIImage(data: NSData(contentsOfURL: NSURL(string: ysCollectionImgArray.objectAtIndex(index) as NSString)!)!)
}
func showNextData(){
if index < ysCollectionImgArray.count - 1 {
index = index + 1
ysBackWordButton.hidden = false
if ysCollectionImgArray.count - 1 == index {
ysForWordButton.hidden = true
}
}
else{
ysForWordButton.hidden = true
ysBackWordButton.hidden = false
// index = 0
}
ysSlideImageView.image = UIImage(data: NSData(contentsOfURL: NSURL(string: ysCollectionImgArray.objectAtIndex(index) as NSString)!)!)
}

How to set up a delay in a CADisplayLink

I am using a CADisplayLink to animate 10 different buttons but the buttons are all clumped together. So my question is how can I implement a delay to make each button animate at a different time so they are not all clumped together.
var buttons:[UIButton] = Array()
override func viewDidLoad() {
super.viewDidLoad()
var displayLink = CADisplayLink(target: self, selector: "handleDisplayLink:")
displayLink.addToRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
for index in 0...10 - 1{
buttons.append(UIButton.buttonWithType(.System) as UIButton)
var xLocation:CGFloat = CGFloat(arc4random_uniform(300) + 30)
buttons[index].frame = CGRectMake(xLocation, 10, 100, 100)
buttons[index].setTitle("Test Button \(index)", forState: UIControlState.Normal)
buttons[index].addTarget(self, action: "buttonAction:", forControlEvents: UIControlEvents.TouchUpInside)
self.view.addSubview(buttons[index])
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func handleDisplayLink(displayLink: CADisplayLink) {
for index in 0...10 - 1{
var buttonFrame = buttons[index].frame
buttonFrame.origin.y += 1
buttons[index].frame = buttonFrame
if buttons[index].frame.origin.y >= 500 {
displayLink.invalidate()
}
}
}
func buttonAction(sender: UIButton) {
sender.alpha = 0
}
To do animation with delay, you can just use UIView.animateWithDuration function instead of a CADisplayLink. For example
override func viewDidLoad() {
for index in 0...10 - 1{
buttons.append(UIButton.buttonWithType(.System) as UIButton)
var xLocation:CGFloat = CGFloat(arc4random_uniform(300) + 30)
buttons[index].frame = CGRectMake(xLocation, 10, 100, 100)
buttons[index].setTitle("Test Button \(index)", forState: UIControlState.Normal)
buttons[index].addTarget(self, action: "buttonAction:", forControlEvents: UIControlEvents.TouchUpInside)
self.view.addSubview(buttons[index])
// Change this line to change the delay between the button animations.
let delay : NSTimeInterval = 1.0 * NSTimeInterval(index)
UIView.animateWithDuration(2.0, delay: delay, options: UIViewAnimationOptions.CurveLinear, animations: { () -> Void in
var buttonFrame = self.buttons[index].frame
buttonFrame.origin.y = 500
self.buttons[index].frame = buttonFrame
}, completion: { (finished) -> Void in
})
}
}

How to recognize swipe in all 4 directions

I need to use swipe to recognize swipe gesture down and then right. But on swift UISwipeGestureRecognizer has predeterminate Right direction.. And I don't know how make this for use other directions..
You need to have one UISwipeGestureRecognizer for each direction. It's a little weird because the UISwipeGestureRecognizer.direction property is an options-style bit mask, but each recognizer can only handle one direction. You can send them all to the same handler if you want, and sort it out there, or send them to different handlers. Here's one implementation:
override func viewDidLoad() {
super.viewDidLoad()
let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(respondToSwipeGesture))
swipeRight.direction = .right
self.view.addGestureRecognizer(swipeRight)
let swipeDown = UISwipeGestureRecognizer(target: self, action: #selector(respondToSwipeGesture))
swipeDown.direction = .down
self.view.addGestureRecognizer(swipeDown)
}
#objc func respondToSwipeGesture(gesture: UIGestureRecognizer) {
if let swipeGesture = gesture as? UISwipeGestureRecognizer {
switch swipeGesture.direction {
case .right:
print("Swiped right")
case .down:
print("Swiped down")
case .left:
print("Swiped left")
case .up:
print("Swiped up")
default:
break
}
}
}
Swift 3:
override func viewDidLoad() {
super.viewDidLoad()
let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(self.respondToSwipeGesture))
swipeRight.direction = UISwipeGestureRecognizerDirection.right
self.view.addGestureRecognizer(swipeRight)
let swipeDown = UISwipeGestureRecognizer(target: self, action: #selector(self.respondToSwipeGesture))
swipeDown.direction = UISwipeGestureRecognizerDirection.down
self.view.addGestureRecognizer(swipeDown)
}
func respondToSwipeGesture(gesture: UIGestureRecognizer) {
if let swipeGesture = gesture as? UISwipeGestureRecognizer {
switch swipeGesture.direction {
case UISwipeGestureRecognizerDirection.right:
print("Swiped right")
case UISwipeGestureRecognizerDirection.down:
print("Swiped down")
case UISwipeGestureRecognizerDirection.left:
print("Swiped left")
case UISwipeGestureRecognizerDirection.up:
print("Swiped up")
default:
break
}
}
}
I just felt like contributing this, looks more elegant in the end:
func addSwipe() {
let directions: [UISwipeGestureRecognizerDirection] = [.Right, .Left, .Up, .Down]
for direction in directions {
let gesture = UISwipeGestureRecognizer(target: self, action: Selector("handleSwipe:"))
gesture.direction = direction
self.addGestureRecognizer(gesture)
}
}
func handleSwipe(sender: UISwipeGestureRecognizer) {
print(sender.direction)
}
From the storyboard:
Add four swipe gesture recognizers to your view.
Set each one with the target direction from the attribute inspector. You can
select right, left, up or down
One by one, select the swipe gesture recognizer, control + drag to your view controller. Insert the name (let us say leftGesture, rightGesture, upGesture and
downGesture), change the connection to: Action and type to:
UISwipeGestureRecognizer
From your viewController:
#IBAction func rightGesture(sender: UISwipeGestureRecognizer) {
print("Right")
}
#IBAction func leftGesture(sender: UISwipeGestureRecognizer) {
print("Left")
}
#IBAction func upGesture(sender: UISwipeGestureRecognizer) {
print("Up")
}
#IBAction func downGesture(sender: UISwipeGestureRecognizer) {
print("Down")
}
Looks like things have changed lately. In XCode 7.2 the following approach works:
override func viewDidLoad() {
super.viewDidLoad()
let swipeGesture = UISwipeGestureRecognizer(target: self, action: "handleSwipe:")
swipeGesture.direction = [.Down, .Up]
self.view.addGestureRecognizer(swipeGesture)
}
func handleSwipe(sender: UISwipeGestureRecognizer) {
print(sender.direction)
}
Tested in Simulator on iOS 8.4 and 9.2 and on actual device on 9.2.
Or, using mlcollard's handy extension here:
let swipeGesture = UISwipeGestureRecognizer() {
print("Gesture recognized !")
}
swipeGesture.direction = [.Down, .Up]
self.view.addGestureRecognizer(swipeGesture)
Apple Swift version 3.1 - Xcode Version 8.3 (8E162)
The handy way from Alexandre Cassagne's approach
let directions: [UISwipeGestureRecognizerDirection] = [.up, .down, .right, .left]
for direction in directions {
let gesture = UISwipeGestureRecognizer(target: self, action: #selector(YourClassName.handleSwipe(gesture:)))
gesture.direction = direction
self.view?.addGestureRecognizer(gesture)
}
func handleSwipe(gesture: UISwipeGestureRecognizer) {
print(gesture.direction)
switch gesture.direction {
case UISwipeGestureRecognizerDirection.down:
print("down swipe")
case UISwipeGestureRecognizerDirection.up:
print("up swipe")
case UISwipeGestureRecognizerDirection.left:
print("left swipe")
case UISwipeGestureRecognizerDirection.right:
print("right swipe")
default:
print("other swipe")
}
}
In Swift 4.2 and Xcode 9.4.1
Add Animation delegate, CAAnimationDelegate to your class
//Swipe gesture for left and right
let swipeFromRight = UISwipeGestureRecognizer(target: self, action: #selector(didSwipeLeft))
swipeFromRight.direction = UISwipeGestureRecognizerDirection.left
menuTransparentView.addGestureRecognizer(swipeFromRight)
let swipeFromLeft = UISwipeGestureRecognizer(target: self, action: #selector(didSwipeRight))
swipeFromLeft.direction = UISwipeGestureRecognizerDirection.right
menuTransparentView.addGestureRecognizer(swipeFromLeft)
//Swipe gesture selector function
#objc func didSwipeLeft(gesture: UIGestureRecognizer) {
//We can add some animation also
DispatchQueue.main.async(execute: {
let animation = CATransition()
animation.type = kCATransitionReveal
animation.subtype = kCATransitionFromRight
animation.duration = 0.5
animation.delegate = self
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
//Add this animation to your view
self.transparentView.layer.add(animation, forKey: nil)
self.transparentView.removeFromSuperview()//Remove or hide your view if requirement.
})
}
//Swipe gesture selector function
#objc func didSwipeRight(gesture: UIGestureRecognizer) {
// Add animation here
DispatchQueue.main.async(execute: {
let animation = CATransition()
animation.type = kCATransitionReveal
animation.subtype = kCATransitionFromLeft
animation.duration = 0.5
animation.delegate = self
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
//Add this animation to your view
self.transparentView.layer.add(animation, forKey: nil)
self.transparentView.removeFromSuperview()//Remove or hide yourview if requirement.
})
}
If you want to remove gesture from view use this code
self.transparentView.removeGestureRecognizer(gesture)
Ex:
func willMoveFromView(view: UIView) {
if view.gestureRecognizers != nil {
for gesture in view.gestureRecognizers! {
//view.removeGestureRecognizer(gesture)//This will remove all gestures including tap etc...
if let recognizer = gesture as? UISwipeGestureRecognizer {
//view.removeGestureRecognizer(recognizer)//This will remove all swipe gestures
if recognizer.direction == .left {//Especially for left swipe
view.removeGestureRecognizer(recognizer)
}
}
}
}
}
Call this function like
//Remove swipe gesture
self.willMoveFromView(view: self.transparentView)
Like this you can write remaining directions and please careful whether if you have scroll view or not from bottom to top and vice versa
If you have scroll view, you will get conflict for Top to bottom and view versa gestures.
Swipe gesture to the view you want, or viewcontroller whole view in Swift 5 & XCode 11 based on #Alexandre Cassagne
override func viewDidLoad() {
super.viewDidLoad()
addSwipe()
}
func addSwipe() {
let directions: [UISwipeGestureRecognizer.Direction] = [.right, .left, .up, .down]
for direction in directions {
let gesture = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipe))
gesture.direction = direction
self.myView.addGestureRecognizer(gesture)// self.view
}
}
#objc func handleSwipe(sender: UISwipeGestureRecognizer) {
let direction = sender.direction
switch direction {
case .right:
print("Gesture direction: Right")
case .left:
print("Gesture direction: Left")
case .up:
print("Gesture direction: Up")
case .down:
print("Gesture direction: Down")
default:
print("Unrecognized Gesture Direction")
}
}
UISwipeGestureRecognizer has a direction property that has the following definition:
var direction: UISwipeGestureRecognizerDirection
The permitted direction of the swipe for this gesture recognizer.
The problem with Swift 3.0.1 (and below) is that even if UISwipeGestureRecognizerDirection conforms to OptionSet, the following snippet will compile but won't produce any positive expected result:
// This compiles but does not work
let gesture = UISwipeGestureRecognizer(target: self, action: #selector(gestureHandler))
gesture.direction = [.right, .left, .up, .down]
self.addGestureRecognizer(gesture)
As a workaround, you will have to create a UISwipeGestureRecognizer for each desired direction.
The following Playground code shows how to implement several UISwipeGestureRecognizer for the same UIView and the same selector using Array's map method:
import UIKit
import PlaygroundSupport
class SwipeableView: UIView {
convenience init() {
self.init(frame: CGRect(x: 100, y: 100, width: 100, height: 100))
backgroundColor = .red
[UISwipeGestureRecognizerDirection.right, .left, .up, .down].map({
let gesture = UISwipeGestureRecognizer(target: self, action: #selector(gestureHandler))
gesture.direction = $0
self.addGestureRecognizer(gesture)
})
}
func gestureHandler(sender: UISwipeGestureRecognizer) {
switch sender.direction {
case [.left]: frame.origin.x -= 10
case [.right]: frame.origin.x += 10
case [.up]: frame.origin.y -= 10
case [.down]: frame.origin.y += 10
default: break
}
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(SwipeableView())
}
}
let controller = ViewController()
PlaygroundPage.current.liveView = controller
Swipe Gesture in Swift 5
override func viewDidLoad() {
super.viewDidLoad()
let swipeLeft = UISwipeGestureRecognizer(target: self, action: #selector(handleGesture))
swipeLeft.direction = .left
self.view!.addGestureRecognizer(swipeLeft)
let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(handleGesture))
swipeRight.direction = .right
self.view!.addGestureRecognizer(swipeRight)
let swipeUp = UISwipeGestureRecognizer(target: self, action: #selector(handleGesture))
swipeUp.direction = .up
self.view!.addGestureRecognizer(swipeUp)
let swipeDown = UISwipeGestureRecognizer(target: self, action: #selector(handleGesture))
swipeDown.direction = .down
self.view!.addGestureRecognizer(swipeDown)
}
#objc func handleGesture(gesture: UISwipeGestureRecognizer) -> Void {
if gesture.direction == UISwipeGestureRecognizer.Direction.right {
print("Swipe Right")
}
else if gesture.direction == UISwipeGestureRecognizer.Direction.left {
print("Swipe Left")
}
else if gesture.direction == UISwipeGestureRecognizer.Direction.up {
print("Swipe Up")
}
else if gesture.direction == UISwipeGestureRecognizer.Direction.down {
print("Swipe Down")
}
}
After digging around for a while:
The shortest way to add swipes for all 4 directions is:
override func viewDidLoad() {
super.viewDidLoad()
for direction in [UISwipeGestureRecognizer.Direction.down, .up, .left, .right]{
let swipeGest = UISwipeGestureRecognizer(target: self, action: #selector(swipeAction(_:)))
swipeGest.direction = direction
self.view.addGestureRecognizer(swipeGest)
}
}
#objc func swipeAction(_ gesture: UISwipeGestureRecognizer){
switch gesture.direction {
case UISwipeGestureRecognizer.Direction.right:
print("Swiped right")
case UISwipeGestureRecognizer.Direction.down:
print("Swiped down")
case UISwipeGestureRecognizer.Direction.left:
print("Swiped left")
case UISwipeGestureRecognizer.Direction.up:
print("Swiped up")
default: break
}
In Swift 5,
let swipeGesture = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipe))
swipeGesture.direction = [.left, .right, .up, .down]
view.addGestureRecognizer(swipeGesture)
EDİT: "swift5.3"
First create a baseViewController and add viewDidLoad this code :
class BaseViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(swiped))
swipeRight.direction = .right
self.view.addGestureRecognizer(swipeRight)
let swipeLeft = UISwipeGestureRecognizer(target: self, action: #selector(swiped))
swipeLeft.direction = .left
self.view.addGestureRecognizer(swipeLeft)
}
// Example Tabbar 5 pages
#objc func swiped(_ gesture: UISwipeGestureRecognizer) {
if gesture.direction == .left {
if (self.tabBarController?.selectedIndex)! < 5 {
self.tabBarController?.selectedIndex += 1
}
} else if gesture.direction == .right {
if (self.tabBarController?.selectedIndex)! > 0 {
self.tabBarController?.selectedIndex -= 1
}
}
}
}
And use this baseController class:
class YourViewController: BaseViewController {
// its done. Swipe successful
//Now you can use all the Controller you have created without writing any code.
}
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let leftside = UISwipeGestureRecognizer(target: self, action: #selector(swiped))
leftside.direction = .left
view.addGestureRecognizer(leftside)
let rightside = UISwipeGestureRecognizer(target: self, action: #selector(swiped))
rightside.direction = .right
view.addGestureRecognizer(rightside)
let upside = UISwipeGestureRecognizer(target: self, action: #selector(swiped))
upside.direction = .up
view.addGestureRecognizer(upside)
let downside = UISwipeGestureRecognizer(target: self, action: #selector(swiped))
downside.direction = .down
view.addGestureRecognizer(downside)
// Do any additional setup after loading the view, typically from a nib.
}
#objc func swiped(gesture: UIGestureRecognizer){
if let swipeGesture = gesture as? UISwipeGestureRecognizer{
switch swipeGesture.direction{
case UISwipeGestureRecognizer.Direction.left:
view.backgroundColor = UIColor.red
case UISwipeGestureRecognizer.Direction.right:
view.backgroundColor = UIColor.yellow
case UISwipeGestureRecognizer.Direction.up:
view.backgroundColor = UIColor.green
case UISwipeGestureRecognizer.Direction.down:
view.backgroundColor = UIColor.blue
default:
"ERROR"
}
}
}
}
Swift 5+
Add desired gestures to some UIView:
[UISwipeGestureRecognizer.Direction.up, .down, .left, .right].forEach {
let gesture = UISwipeGestureRecognizer(target: self, action: #selector(swiped))
gesture.direction = $0
someView.addGestureRecognizer(gesture)
}
Handle swipe actions:
#objc func swiped(_ gesture: UISwipeGestureRecognizer) {
switch gesture.direction {
case .up: print("up")
case .down: print("down")
case .left: print("left")
case .right: print("right")
default: break
}
}
I like #Fattie's approach (extension), which is what I've been using for tap gestures for a long time, except as an extension of UIView, instead of UIViewController. It is a great time saving convenience. Since you may not want to enable all four cartesian direction,s I default to nil for each selector to check for presence of parameters to make activation of gesture for any given direction optional.
I made the parameter names a little bit longer to speed up reverse engineering when skimming code and overloaded the function name, because why not?
extension UIView {
func addSwipeRecognizer(direction: UISwipeGestureRecognizer.Direction, target: Any, action: Selector) {
let recognizer = UISwipeGestureRecognizer(target: target, action: action)
recognizer.direction = direction
addGestureRecognizer(recognizer)
}
func addSwipeRecognizer(target: Any, left: Selector? = nil, right: Selector? = nil, up: Selector? = nil, down: Selector? = nil) {
if let left { addSwipeRecognizer(direction: .left, target: target, action: left) }
if let right { addSwipeRecognizer(direction: .right, target: target, action: right) }
if let up { addSwipeRecognizer(direction: .up, target: target, action: up) }
if let down { addSwipeRecognizer(direction: .down, target: target, action: down) }
}
func addTapRecognizer(tapNumber: Int, target: Any, action: Selector) {
let tap = UITapGestureRecognizer(target: target, action: action)
tap.numberOfTapsRequired = tapNumber
addGestureRecognizer(tap)
isUserInteractionEnabled = true
}
}
Usage:
#objc func viewSwipedLeft() { }
#objc func viewSwipedRight() { }
#objc func viewSwipedUp() { }
#objc func viewSwipedDown() { }
view.addSwipeRecognizer(target: self,
left: #selector(viewSwipedLeft),
right: #selector(viewSwipedRight),
up: #selector(viewSwipedUp),
down: #selector(viewSwipedDown))
Just a cooler swift syntax for Nate's answer:
[UISwipeGestureRecognizerDirection.right,
UISwipeGestureRecognizerDirection.left,
UISwipeGestureRecognizerDirection.up,
UISwipeGestureRecognizerDirection.down].forEach({ direction in
let swipe = UISwipeGestureRecognizer(target: self, action: #selector(self.respondToSwipeGesture))
swipe.direction = direction
self.view.addGestureRecognizer(swipe)
})
Easy. Just follow the code below and enjoy.
//SwipeGestureMethodUsing
func SwipeGestureMethodUsing ()
{
//AddSwipeGesture
[UISwipeGestureRecognizerDirection.right,
UISwipeGestureRecognizerDirection.left,
UISwipeGestureRecognizerDirection.up,
UISwipeGestureRecognizerDirection.down].forEach({ direction in
let swipe = UISwipeGestureRecognizer(target: self, action: #selector(self.respondToSwipeGesture))
swipe.direction = direction
window?.addGestureRecognizer(swipe)
})
}
//respondToSwipeGesture
func respondToSwipeGesture(gesture: UIGestureRecognizer) {
if let swipeGesture = gesture as? UISwipeGestureRecognizer
{
switch swipeGesture.direction
{
case UISwipeGestureRecognizerDirection.right:
print("Swiped right")
case UISwipeGestureRecognizerDirection.down:
print("Swiped down")
case UISwipeGestureRecognizerDirection.left:
print("Swiped left")
case UISwipeGestureRecognizerDirection.up:
print("Swiped up")
default:
break
}
}
}
For Swift 5 it's updated
//Add in ViewDidLoad
let gesture = UISwipeGestureRecognizer(target: self, action: #selector(ViewController.handleSwipe))
gesture.direction = .right
self.view.addGestureRecognizer(gesture)
//Add New Method
#objc func handleSwipe(sender: UISwipeGestureRecognizer) {
print("swipe direction is",sender.direction)
}
For 2022
Here's how you'd probably write it in any real-life code.
You'd never clutter your VC code with all the boilerplate.
In your view controller ...
override func viewDidLoad() {
super.viewDidLoad()
pentaSceneView.buildFresh()
addSwipesLRUD(#selector(swipeLeft), #selector(swipeRight),
#selector(swipeUp), #selector(swipeDown))
}
and ...
#objc func swipeLeft() {
blah ...
}
#objc func swipeRight() {
blah ...
}
#objc func swipeUp() {
blah ...
}
#objc func swipeDown() {
blah ...
}
Should you use a switch statement? Answer: NO, don't.
Apple's code for .direction is not so much broken, but just "incredibly stupid", and they keep changing it. A switch statement is neither more elegant nor shorter than having four functions, and it will very likely break when Apple (again) slightly change or rationalize the way .direction works.
Here's the simple extension needed.
Put this in any file in your project, say, "Utils.swift". Every real-world project has an "extensions in here" type file, where, you keep very common extensions you use in all projects.
extension UIViewController {
///Add a UISwipeGestureRecognizer.
func addSwipe(_ d: UISwipeGestureRecognizer.Direction, _ s: Selector) {
let g = UISwipeGestureRecognizer(target: self, action: s)
g.direction = d
view.addGestureRecognizer(g)
}
///Add four swipes for left right up down.
func addSwipesLRUD(_ l: Selector, _ r: Selector, _ u: Selector, _ d: Selector) {
addSwipe(.left, l)
addSwipe(.right, r)
addSwipe(.up, u)
addSwipe(.down, d)
}
}
It can be done by simply declaring one function which will handle all your swipe UISwipeGestureRecognizer directions. Here is my code:
let swipeGestureRight = UISwipeGestureRecognizer(target: self, action:#selector(ViewController.respondToSwipeGesture(_:)) )
swipeGestureRight.direction = UISwipeGestureRecognizerDirection.right
self.view .addGestureRecognizer(swipeGestureRight)
let swipeGestureLeft = UISwipeGestureRecognizer(target: self, action: #selector(ViewController.respondToSwipeGesture(_:)))
swipeGestureLeft.direction = UISwipeGestureRecognizerDirection.left
self.view.addGestureRecognizer(swipeGestureLeft)
let swipeGestureUp = UISwipeGestureRecognizer(target: self, action: #selector(ViewController.respondToSwipeGesture(_:)))
swipeGestureUp.direction = UISwipeGestureRecognizerDirection.up
self.view.addGestureRecognizer(swipeGestureUp)
let swipeGestureDown = UISwipeGestureRecognizer(target: self, action: #selector(ViewController.respondToSwipeGesture(_:)))
swipeGestureDown.direction = UISwipeGestureRecognizerDirection.down
self.view.addGestureRecognizer(swipeGestureDown)
Here is the function which will hande the swipedirection functionality:
func respondToSwipeGesture(_ sender: UIGestureRecognizer) {
if let swipeGesture = sender as? UISwipeGestureRecognizer {
switch swipeGesture.direction {
case UISwipeGestureRecognizerDirection.right:
print("right swipe")
case UISwipeGestureRecognizerDirection.left:
print("leftSwipe")
case UISwipeGestureRecognizerDirection.up:
print("upSwipe")
case UISwipeGestureRecognizerDirection.down:
print("downSwipe")
default:
break
}
}
}

Resources