Swipe actions in Swift
The issue:
Gestures, delegates, it can be a big struggle (especially for beginners).
If you use a lot of gestures then you’ll need to implement it over and over.
One of the problems is, that code what you write will not apply to other views in your application.
If we use a lot of swipe actions, in different places within our application we want to have reusable code.
But then we see ourselfs overloaded with issues, can it be made more easy?
Yes!
How can we make it more easy?
Using a UIViewextension.
Why not a UIViewController?
“Because we also want to support other applications which have a UIView
.”
How do we start?
In this post we’ll start with a UIView extension, to make it reusable for other applications (e.g. UIImageView, UIView, ...).
In my case it didn’t work on a UITableViewController
.
Psuedo code:
import Foundation
import UIKit
extension UIView {
// psuedo code continues
We also need a variable, but simply var myVariable = ...does not work, since we are working in an extension.
There is a workaround, and it may be more easy than you think.
We’ll use a structand that will solve all our variable problems.
We want to reuse the data, so we make a static var.
Psuedo code:
// .... psuedo code to above blocks<br>struct gestureClosures {
static var up = ...
static var down = ...
static var left = ...
static var right = ...
}
We also need to create a function, to make it work!
Psuedo code:
func swipeAction(
swipeDirection: UISwipeGestureRecognizer.Direction,
completionHandler: @escaping ()->()
) {
// Add a swiper
let swiper = .... #selector(self.invokeTarget(_:))
// give the direction as in swipeDirection
swiper.direction = swipeDirection
// add to the view
self.addGestureRecognizer(swiper)
// save the completionHandler
switch swipeDirection {
case .up:
gestureClosures.up = completionHandler
case .down:
gestureClosures.down = completionHandler
case .left:
gestureClosures.left = completionHandler
case .right:
gestureClosures.right = completionHandler
default:
print("Nothing")
}
}
But we still need to respond on the swipe actions!
Yup, pseudocode:
@objc func invokeTarget(...) {
// disamble
switch swipeDirection {
case .up:
gestureClosures.up()
case .down:
gestureClosures.down()
case .left:
gestureClosures.left()
case .right:
gestureClosures.righ()
default:
print("Nothing")
}
}
And if we translate it to functional swift code.
Then the output looks similair to above.
The complete solution:
import Foundation
import UIKit
// Extend UIView
extension UIView {
/// Setup a struct for saving the gesture handlers
struct gestureHandler {
/// Gesture "Up"
static var up: (()->())? = nil
/// Gesture "Down"
static var down: (()->())? = nil
/// Gesture "Left"
static var left: (()->())? = nil
/// Gesture "Right"
static var right: (()->())? = nil
}
/**
* Add a swipe action to UIView
*
* - Parameter swipeDirection: `.up`,`.down`,`.left`,`.right`
* - Parameter completionHandler: The completionhandler.
*/
func swipeAction(
swipeDirection: UISwipeGestureRecognizer.Direction,
completionHandler: @escaping ()->()
) {
/// Add swipe handler
let swiper = UISwipeGestureRecognizer(
// UIView is the target
target: self,
// invokeTarget is our responder
action: #selector(self.invokeTarget(_:))
)
// Set the direction of the swipe handler
swiper.direction = swipeDirection
// Add the gesture recognizer to the view
self.addGestureRecognizer(swiper)
// Switch between directions,
// Save it to our struct.
switch swipeDirection {
case .up:
// Save the completionHandler to gestureHandler.up
gestureHandler.up = completionHandler
case .down:
// Save the completionHandler to gestureHandler.down
gestureHandler.down = completionHandler
case .left:
// Save the completionHandler to gestureHandler.left
gestureHandler.left = completionHandler
case .right:
// Save the completionHandler to gestureHandler.right
gestureHandler.right = completionHandler
default:
print("Nothing")
}
}
/**
* Respond to a swipe action from UIView
*
* - Parameter gesture: The UIGestureRecognizer
*/
@objc func invokeTarget(_ gesture: UIGestureRecognizer?) {
/// Unwrap the swipeGesture
if let swipeGesture = gesture as? UISwipeGestureRecognizer {
// Switch between the direction
switch swipeGesture.direction {
case .up:
/// Unwrap gestureHandler.up if possible
guard let execute = gestureHandler.up else {
return
}
execute()
break;
case .down:
/// Unwrap gestureHandler.down if possible
guard let execute = gestureHandler.down else {
return
}
execute()
break;
case .left:
/// Unwrap gestureHandler.left if possible
guard let execute = gestureHandler.left else {
return
}
execute()
break;
case .right:
/// Unwrap gestureHandler.right if possible
guard let execute = gestureHandler.right else {
return
}
execute()
break;
default:
print("N/A")
}
}
}
}
Read more
- Safely unwrap optional values in SwiftUI bindings • 4 minutes reading time.
- Snippet: @EnvironmentVariable • 1 minutes reading time.
- How to monitor network in SwiftUI • 3 minutes reading time.
Share
Share Mastodon Twitter LinkedIn Facebook