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)!)!)
}
Related
I have a canvasImageView and draw something on it.
And I want to output an image just contain image region.
My output function is func saveBtnPressed(sender: UIButton).
Like following image, I want to output blue line region.
Have any idea to do this?
Thanks.
class CanvasViewController: UIViewController {
let canvasImageView: CanvasImageView = {
let ui = CanvasImageView()
ui.contentMode = .scaleAspectFit
ui.layer.backgroundColor = UIColor.clear.cgColor
ui.backgroundColor = UIColor.clear
ui.clipsToBounds = true
ui.isMultipleTouchEnabled = false
ui.isUserInteractionEnabled = true
return ui
}()
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Color Yourself"
let save = UIBarButtonItem(barButtonSystemItem: .save, target: self, action: #selector(saveBtnPressed(sender:)))
let redo = UIBarButtonItem(barButtonSystemItem: .refresh, target: self, action: #selector(clearBtnPressed(sender:)))
let back = UIBarButtonItem(barButtonSystemItem: .stop, target: self, action: #selector(cancelBtnPressed(sender:)))
self.navigationItem.rightBarButtonItems = [save, redo]
self.navigationItem.leftBarButtonItem = back
self.setupView()
}
fileprivate func setupView() {
self.view.addSubview(canvasImageView)
if #available(iOS 11.0, *) {
self.canvasImageView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 0).isActive = true
} else {
self.canvasImageView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor, constant: 0).isActive = true
}
self.canvasImageView.snp.makeConstraints { (make) in
make.bottom.left.right.equalToSuperview()
}
}
//MARK: BUTTON ACTION
#objc func cancelBtnPressed(sender: UIBarButtonItem) {
self.dismiss(animated: false, completion: nil)
}
#objc func clearBtnPressed(sender: UIButton) {
canvasImageView.clearCanvas()
}
#objc func saveBtnPressed(sender: UIButton) {
//Here is output image.
UIGraphicsBeginImageContextWithOptions(self.canvasImageView.layer.bounds.size, true, 0.0)
self.canvasImageView.layer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
if let img = image {
UIImageWriteToSavedPhotosAlbum(img, self,#selector(image(_:didFinishSavingWithError:contextInfo:)), nil)
}
}
}
class CanvasImageView: UIImageView {
var lineColor = UIColor.red
var lineWidth: CGFloat = 10
var path: UIBezierPath?
var touchPoint: CGPoint!
var startingPoint: CGPoint!
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.startingPoint = touches.first?.location(in: self)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
self.touchPoint = touches.first?.location(in: self)
self.path = UIBezierPath()
path?.move(to: startingPoint)
path?.addLine(to: touchPoint)
self.startingPoint = touchPoint
self.draw()
}
func draw() {
let shapeLayer = CAShapeLayer()
shapeLayer.path = path?.cgPath
shapeLayer.strokeColor = lineColor.cgColor
shapeLayer.lineWidth = lineWidth
shapeLayer.fillColor = UIColor.clear.cgColor
self.layer.addSublayer(shapeLayer)
self.setNeedsDisplay()
}
func clearCanvas() {
guard let drawPath = path else { return }
drawPath.removeAllPoints()
self.layer.sublayers = nil
self.setNeedsDisplay()
}
}
I have used UIPinchGestureRecognizer UIPanGestureRecognizer & UIRotationGestureRecognizer with UILabel to achieve Instagram like zoom and drag functionality. Now I would like to show layout guide like when UILabel is dragged in center it should show layout guide like below example. It should also display layout guide when you rotate UILabel.
What is the best and accurate possible way to achieve this functionality?
This is what I already have
(Image taken from this question by #Skiddswarmik)
Here is code I have for simple drag and zoom functionality (taken from this answer by #lbsweek)
SnapGesture Class
import UIKit
/*
usage:
add gesture:
yourObjToStoreMe.snapGesture = SnapGesture(view: your_view)
remove gesture:
yourObjToStoreMe.snapGesture = nil
disable gesture:
yourObjToStoreMe.snapGesture.isGestureEnabled = false
advanced usage:
view to receive gesture(usually superview) is different from view to be transformed,
thus you can zoom the view even if it is too small to be touched.
yourObjToStoreMe.snapGesture = SnapGesture(transformView: your_view_to_transform, gestureView: your_view_to_recieve_gesture)
*/
class SnapGesture: NSObject, UIGestureRecognizerDelegate {
// MARK: - init and deinit
convenience init(view: UIView) {
self.init(transformView: view, gestureView: view)
}
init(transformView: UIView, gestureView: UIView) {
super.init()
self.addGestures(v: gestureView)
self.weakTransformView = transformView
}
deinit {
self.cleanGesture()
}
// MARK: - private method
private weak var weakGestureView: UIView?
private weak var weakTransformView: UIView?
private var panGesture: UIPanGestureRecognizer?
private var pinchGesture: UIPinchGestureRecognizer?
private var rotationGesture: UIRotationGestureRecognizer?
private func addGestures(v: UIView) {
panGesture = UIPanGestureRecognizer(target: self, action: #selector(panProcess(_:)))
v.isUserInteractionEnabled = true
panGesture?.delegate = self // for simultaneous recog
v.addGestureRecognizer(panGesture!)
pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(pinchProcess(_:)))
//view.isUserInteractionEnabled = true
pinchGesture?.delegate = self // for simultaneous recog
v.addGestureRecognizer(pinchGesture!)
rotationGesture = UIRotationGestureRecognizer(target: self, action: #selector(rotationProcess(_:)))
rotationGesture?.delegate = self
v.addGestureRecognizer(rotationGesture!)
self.weakGestureView = v
}
private func cleanGesture() {
if let view = self.weakGestureView {
//for recognizer in view.gestureRecognizers ?? [] {
// view.removeGestureRecognizer(recognizer)
//}
if panGesture != nil {
view.removeGestureRecognizer(panGesture!)
panGesture = nil
}
if pinchGesture != nil {
view.removeGestureRecognizer(pinchGesture!)
pinchGesture = nil
}
if rotationGesture != nil {
view.removeGestureRecognizer(rotationGesture!)
rotationGesture = nil
}
}
self.weakGestureView = nil
self.weakTransformView = nil
}
// MARK: - API
private func setView(view:UIView?) {
self.setTransformView(view, gestgureView: view)
}
private func setTransformView(_ transformView: UIView?, gestgureView:UIView?) {
self.cleanGesture()
if let v = gestgureView {
self.addGestures(v: v)
}
self.weakTransformView = transformView
}
open func resetViewPosition() {
UIView.animate(withDuration: 0.4) {
self.weakTransformView?.transform = CGAffineTransform.identity
}
}
open var isGestureEnabled = true
// MARK: - gesture handle
// location will jump when finger number change
private var initPanFingerNumber:Int = 1
private var isPanFingerNumberChangedInThisSession = false
private var lastPanPoint:CGPoint = CGPoint(x: 0, y: 0)
#objc func panProcess(_ recognizer:UIPanGestureRecognizer) {
if isGestureEnabled {
//guard let view = recognizer.view else { return }
guard let view = self.weakTransformView else { return }
// init
if recognizer.state == .began {
lastPanPoint = recognizer.location(in: view)
initPanFingerNumber = recognizer.numberOfTouches
isPanFingerNumberChangedInThisSession = false
}
// judge valid
if recognizer.numberOfTouches != initPanFingerNumber {
isPanFingerNumberChangedInThisSession = true
}
if isPanFingerNumberChangedInThisSession {
return
}
// perform change
let point = recognizer.location(in: view)
view.transform = view.transform.translatedBy(x: point.x - lastPanPoint.x, y: point.y - lastPanPoint.y)
lastPanPoint = recognizer.location(in: view)
}
}
private var lastScale:CGFloat = 1.0
private var lastPinchPoint:CGPoint = CGPoint(x: 0, y: 0)
#objc func pinchProcess(_ recognizer:UIPinchGestureRecognizer) {
if isGestureEnabled {
guard let view = self.weakTransformView else { return }
// init
if recognizer.state == .began {
lastScale = 1.0;
lastPinchPoint = recognizer.location(in: view)
}
// judge valid
if recognizer.numberOfTouches < 2 {
lastPinchPoint = recognizer.location(in: view)
return
}
// Scale
let scale = 1.0 - (lastScale - recognizer.scale);
view.transform = view.transform.scaledBy(x: scale, y: scale)
lastScale = recognizer.scale;
// Translate
let point = recognizer.location(in: view)
view.transform = view.transform.translatedBy(x: point.x - lastPinchPoint.x, y: point.y - lastPinchPoint.y)
lastPinchPoint = recognizer.location(in: view)
}
}
#objc func rotationProcess(_ recognizer: UIRotationGestureRecognizer) {
if isGestureEnabled {
guard let view = self.weakTransformView else { return }
view.transform = view.transform.rotated(by: recognizer.rotation)
recognizer.rotation = 0
}
}
//MARK:- UIGestureRecognizerDelegate Methods
func gestureRecognizer(_: UIGestureRecognizer,
shouldRecognizeSimultaneouslyWith shouldRecognizeSimultaneouslyWithGestureRecognizer:UIGestureRecognizer) -> Bool {
return true
}
}
Add Gesture in UILabel
// define
var snapGesture: SnapGesture?
// add gesture
self.snapGesture = SnapGesture(view: self.myLabel!)
Below you will find an updated version of your class that should do what you describe.
Most of the updated code is located at the last section (Guides) near the end, but I have updated your UIGestureRecognizer actions a bit as well as your main init method.
Features:
- A vertical guide for centering a view's position horizontally.
- A horizontal guide for centering a view's rotation at 0 degrees.
- Position and rotation snapping to guides with tolerance values (snapToleranceDistance and snapToleranceAngle properties).
- Animated appearance / disappearance of guides (animateGuides and guideAnimationDuration properties).
- Guide views that can be changed per use case (movementGuideView and rotationGuideView properties)
class SnapGesture: NSObject, UIGestureRecognizerDelegate {
// MARK: - init and deinit
convenience init(view: UIView) {
self.init(transformView: view, gestureView: view)
}
init(transformView: UIView, gestureView: UIView) {
super.init()
self.addGestures(v: gestureView)
self.weakTransformView = transformView
guard let transformView = self.weakTransformView, let superview = transformView.superview else {
return
}
// This is required in order to be able to snap the view to center later on,
// using the `tx` property of its transform.
transformView.center = superview.center
}
deinit {
self.cleanGesture()
}
// MARK: - private method
private weak var weakGestureView: UIView?
private weak var weakTransformView: UIView?
private var panGesture: UIPanGestureRecognizer?
private var pinchGesture: UIPinchGestureRecognizer?
private var rotationGesture: UIRotationGestureRecognizer?
private func addGestures(v: UIView) {
panGesture = UIPanGestureRecognizer(target: self, action: #selector(panProcess(_:)))
v.isUserInteractionEnabled = true
panGesture?.delegate = self // for simultaneous recog
v.addGestureRecognizer(panGesture!)
pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(pinchProcess(_:)))
//view.isUserInteractionEnabled = true
pinchGesture?.delegate = self // for simultaneous recog
v.addGestureRecognizer(pinchGesture!)
rotationGesture = UIRotationGestureRecognizer(target: self, action: #selector(rotationProcess(_:)))
rotationGesture?.delegate = self
v.addGestureRecognizer(rotationGesture!)
self.weakGestureView = v
}
private func cleanGesture() {
if let view = self.weakGestureView {
//for recognizer in view.gestureRecognizers ?? [] {
// view.removeGestureRecognizer(recognizer)
//}
if panGesture != nil {
view.removeGestureRecognizer(panGesture!)
panGesture = nil
}
if pinchGesture != nil {
view.removeGestureRecognizer(pinchGesture!)
pinchGesture = nil
}
if rotationGesture != nil {
view.removeGestureRecognizer(rotationGesture!)
rotationGesture = nil
}
}
self.weakGestureView = nil
self.weakTransformView = nil
}
// MARK: - API
private func setView(view:UIView?) {
self.setTransformView(view, gestgureView: view)
}
private func setTransformView(_ transformView: UIView?, gestgureView:UIView?) {
self.cleanGesture()
if let v = gestgureView {
self.addGestures(v: v)
}
self.weakTransformView = transformView
}
open func resetViewPosition() {
UIView.animate(withDuration: 0.4) {
self.weakTransformView?.transform = CGAffineTransform.identity
}
}
open var isGestureEnabled = true
// MARK: - gesture handle
// location will jump when finger number change
private var initPanFingerNumber:Int = 1
private var isPanFingerNumberChangedInThisSession = false
private var lastPanPoint:CGPoint = CGPoint(x: 0, y: 0)
#objc func panProcess(_ recognizer:UIPanGestureRecognizer) {
guard isGestureEnabled, let view = self.weakTransformView else { return }
// init
if recognizer.state == .began {
lastPanPoint = recognizer.location(in: view)
initPanFingerNumber = recognizer.numberOfTouches
isPanFingerNumberChangedInThisSession = false
}
// judge valid
if recognizer.numberOfTouches != initPanFingerNumber {
isPanFingerNumberChangedInThisSession = true
}
if isPanFingerNumberChangedInThisSession {
hideGuidesOnGestureEnd(recognizer)
return
}
// perform change
let point = recognizer.location(in: view)
view.transform = view.transform.translatedBy(x: point.x - lastPanPoint.x, y: point.y - lastPanPoint.y)
lastPanPoint = recognizer.location(in: view)
updateMovementGuide()
hideGuidesOnGestureEnd(recognizer)
}
private var lastScale:CGFloat = 1.0
private var lastPinchPoint:CGPoint = CGPoint(x: 0, y: 0)
#objc func pinchProcess(_ recognizer:UIPinchGestureRecognizer) {
guard isGestureEnabled, let view = self.weakTransformView else { return }
// init
if recognizer.state == .began {
lastScale = 1.0;
lastPinchPoint = recognizer.location(in: view)
}
// judge valid
if recognizer.numberOfTouches < 2 {
lastPinchPoint = recognizer.location(in: view)
hideGuidesOnGestureEnd(recognizer)
return
}
// Scale
let scale = 1.0 - (lastScale - recognizer.scale);
view.transform = view.transform.scaledBy(x: scale, y: scale)
lastScale = recognizer.scale;
// Translate
let point = recognizer.location(in: view)
view.transform = view.transform.translatedBy(x: point.x - lastPinchPoint.x, y: point.y - lastPinchPoint.y)
lastPinchPoint = recognizer.location(in: view)
updateMovementGuide()
hideGuidesOnGestureEnd(recognizer)
}
#objc func rotationProcess(_ recognizer: UIRotationGestureRecognizer) {
guard isGestureEnabled, let view = self.weakTransformView else { return }
view.transform = view.transform.rotated(by: recognizer.rotation)
recognizer.rotation = 0
updateRotationGuide()
hideGuidesOnGestureEnd(recognizer)
}
func hideGuidesOnGestureEnd(_ recognizer: UIGestureRecognizer) {
if recognizer.state == .ended {
showMovementGuide(false)
showRotationGuide(false)
}
}
// MARK:- UIGestureRecognizerDelegate Methods
func gestureRecognizer(_: UIGestureRecognizer,
shouldRecognizeSimultaneouslyWith shouldRecognizeSimultaneouslyWithGestureRecognizer:UIGestureRecognizer) -> Bool {
return true
}
// MARK:- Guides
var animateGuides = true
var guideAnimationDuration: TimeInterval = 0.3
var snapToleranceDistance: CGFloat = 5 // pts
var snapToleranceAngle: CGFloat = 1 // degrees
* CGFloat.pi / 180 // (converted to radians)
var movementGuideView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.blue
return view
} ()
var rotationGuideView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.red
return view
} ()
// MARK: Movement guide and snap
func updateMovementGuide() {
guard let transformView = weakTransformView, let superview = transformView.superview else {
return
}
let transformX = transformView.frame.midX
let superX = superview.bounds.midX
if transformX - snapToleranceDistance < superX && transformX + snapToleranceDistance > superX {
transformView.transform.tx = 0
showMovementGuide(true)
} else {
showMovementGuide(false)
}
updateGuideFrames()
}
var isShowingMovementGuide = false
func showMovementGuide(_ shouldShow: Bool) {
guard isShowingMovementGuide != shouldShow,
let transformView = weakTransformView,
let superview = transformView.superview
else { return }
superview.insertSubview(movementGuideView, belowSubview: transformView)
movementGuideView.frame = CGRect(
x: superview.frame.midX,
y: 0,
width: 1,
height: superview.frame.size.height
)
let duration = animateGuides ? guideAnimationDuration : 0
isShowingMovementGuide = shouldShow
UIView.animate(withDuration: duration) { [weak self] in
self?.movementGuideView.alpha = shouldShow ? 1 : 0
}
}
// MARK: Rotation guide and snap
func updateRotationGuide() {
guard let transformView = weakTransformView else {
return
}
let angle = atan2(transformView.transform.b, transformView.transform.a)
if angle > -snapToleranceAngle && angle < snapToleranceAngle {
transformView.transform = transformView.transform.rotated(by: angle * -1)
showRotationGuide(true)
} else {
showRotationGuide(false)
}
}
var isShowingRotationGuide = false
func showRotationGuide(_ shouldShow: Bool) {
guard isShowingRotationGuide != shouldShow,
let transformView = weakTransformView,
let superview = transformView.superview
else { return }
superview.insertSubview(rotationGuideView, belowSubview: transformView)
let duration = animateGuides ? guideAnimationDuration : 0
isShowingRotationGuide = shouldShow
UIView.animate(withDuration: duration) { [weak self] in
self?.rotationGuideView.alpha = shouldShow ? 1 : 0
}
}
func updateGuideFrames() {
guard let transformView = weakTransformView,
let superview = transformView.superview
else { return }
rotationGuideView.frame = CGRect(
x: 0,
y: transformView.frame.midY,
width: superview.frame.size.width,
height: 1
)
}
}
For anyone interested, here's a test project using this class.
I have a collectionViewCell that either plays a video or displays and image.Now the elements in the cell are generated programatically. I added tap gesture to toggle the sound when video play. The gesture recognizer wasn't getting called. I tried to place a button in story and get its action, that also didn't recieve a call. Then, I tried to place a view inside the cell, that also didn't display.
Here is my code with tap gesture:
import UIKit
import AVKit
import AVFoundation
#IBDesignable class CHCollectionImageCell: UICollectionViewCell {
// MARK: Properties
var imgView: UIImageView! = UIImageView()
var screenWidth:CGFloat = 0
var screenHeight:CGFloat = 0
var playerLayer: AVPlayerLayer!
let tapOnCell = UITapGestureRecognizer(target: self, action: #selector (CHCollectionImageCell.changeMuteRegimeVideo))
// MARK: Functions
override func awakeFromNib() {
super.awakeFromNib()
}
func configureCell(insight: InsightModel) {
imgView.removeFromSuperview()
if playerLayer != nil {
playerLayer.removeFromSuperlayer()
playerLayer = nil
}
self.removeGestureRecognizer(tapOnCell)
if insight.isVideo {
guard let unwrappedVideoURLString = insight.videoURL,
let unwrappedVideoURL = URL(string: unwrappedVideoURLString) else {
return
}
let playerItem = AVPlayerItem(url: unwrappedVideoURL)
let player = AVPlayer(playerItem: playerItem)
playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = self.bounds
player.isMuted = false
layer.addSublayer(playerLayer)
addGestureRecognizer(self.tapOnCell)
} else {
imgView.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.width)
imgView.image = UIImage(named: "stone")
imgView.contentMode = UIViewContentMode.scaleAspectFill
imgView.clipsToBounds = true
clipsToBounds = true
addSubview(self.imgView)
}
}
/*
#IBAction func tapToTurnOfSound(_ sender: Any) {
if isInsightViedo{
if let unwrappedPlayer = playerLayer.player {
unwrappedPlayer.isMuted = !unwrappedPlayer.isMuted
}
}
//Even Tried adding view as below in the cell
//let tapView = UIView()
//tapView.backgroundColor = ColorCodes.appThemeColor
//self.addSubview(tapView)
//self.bringSubview(toFront: tapView)
//tapView.addGestureRecognizer(tapOnCell)
}
*/
func configureCell() {
imgView.removeFromSuperview()
if playerLayer != nil {
playerLayer.removeFromSuperlayer()
playerLayer = nil
}
self.removeGestureRecognizer(tapOnCell)
imgView.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.width)
imgView.image = UIImage(named: "stone")
imgView.contentMode = UIViewContentMode.scaleAspectFill
imgView.clipsToBounds = true
clipsToBounds = true
addSubview(self.imgView)
}
func changeMuteRegimeVideo() {
if let unwrappedPlayer = playerLayer.player {
unwrappedPlayer.isMuted = !unwrappedPlayer.isMuted
}
}
}
Iam doing the same thing in my application by using the following code :
let longPressGesture:UILongPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(viewController.longPress(_:)))
longPressGesture.minimumPressDuration = 0.8
longPressGesture.delegate = self
collectionView.addGestureRecognizer(longPressGesture)
and then call the function:
func longPress(_ longPressGestureRecognizer: UILongPressGestureRecognizer) {
if longPressGestureRecognizer.state == UIGestureRecognizerState.began {
let touchPoint = longPressGestureRecognizer.location(in: collectionView)
if eventsTableView.indexPathForRow(at: touchPoint) != nil {
let index = eventsTableView.indexPathForRow(at: touchPoint)//do whatever you want to do with this index
}}}
you can do whatever you want to do in this function. In my case i used this to enlarge the image in the collection view
I need to develop a tableview with edit actions on rows that look similar to the ones on iOS Notification center.
The resources I have used so far, say that I can only edit the background color and width of edit actions. What I want is the custom look like that of the notifications in iOS Notifications Center.
See the annotated portion. This is what I want.
This is what I have managed so far :|
Any help / guidance would be greatly appreciated!
Thanks in advance!
I ended up creating my own views as a part of the table view cell and adding custom animation..
Sample Code:
In my tableViewController:
override func viewDidLoad() {
super.viewDidLoad()
....
let tapGesture = UITapGestureRecognizer.init(target: self, action: #selector(handleTap))
tableView.addGestureRecognizer(tapGesture)
let leftSwipeGesture = UISwipeGestureRecognizer.init(target: self, action: #selector(handleLeftSwipe(_:)))
leftSwipeGesture.direction = .left
tableView.addGestureRecognizer(leftSwipeGesture)
let rightSwipeGesture = UISwipeGestureRecognizer.init(target: self, action: #selector(handleRightSwipe(_:)))
rightSwipeGesture.direction = .right
tableView.addGestureRecognizer(rightSwipeGesture)
}
func handleTap(_ gestureRecognizer: UISwipeGestureRecognizer) {
let point = gestureRecognizer.location(in: self.tableView)
if let indexPath = self.tableView.indexPathForRow(at: point) {
var shouldSelectRow = false
if indexPathBeingEdited != nil {
if indexPath == indexPathBeingEdited {
shouldSelectRow = true
} else {
//handle close of the cell being edited already
if let previousEditedCell = tableView.cellForRow(at: indexPathBeingEdited!) as? NotificationCenterTableViewCell {
previousEditedCell.closeEditActions()
indexPathBeingEdited = nil
}
}
} else {
shouldSelectRow = true
}
if shouldSelectRow {
tableView.selectRow(at: indexPath, animated: true, scrollPosition: .middle)
tableView(tableView, didSelectRowAt: indexPath)
}
}
}
func handleLeftSwipe(_ gestureRecognizer: UISwipeGestureRecognizer) {
let point = gestureRecognizer.location(in: self.tableView)
if let indexPath = self.tableView.indexPathForRow(at: point) {
if indexPathBeingEdited != nil {
if indexPath == indexPathBeingEdited {
//Do nothing
} else {
//handle close of the cell being edited already
if let previousEditedCell = tableView.cellForRow(at: indexPathBeingEdited!) as? NotificationCenterTableViewCell {
previousEditedCell.closeEditActions()
indexPathBeingEdited = nil
}
}
}
//proceed with left swipe action
if let cell = tableView.cellForRow(at: indexPath) as? NotificationCenterTableViewCell {
cell.handleLeftSwipe(gestureRecognizer)
let notification = notificationsArray[indexPath.section].notificationItems[indexPath.row]
//Update the title of Read button
if notification.isNotificationRead {
cell.readUnreadButtonLabel.text = "Unread"
} else {
cell.readUnreadButtonLabel.text = "Read"
}
indexPathBeingEdited = indexPath
}
}
}
func handleRightSwipe(_ gestureRecognizer: UISwipeGestureRecognizer) {
let point = gestureRecognizer.location(in: self.tableView)
if let indexPath = self.tableView.indexPathForRow(at: point) {
if indexPathBeingEdited != nil {
if indexPath == indexPathBeingEdited {
if let cell = tableView.cellForRow(at: indexPath) as? NotificationCenterTableViewCell {
cell.closeEditActions()
indexPathBeingEdited = nil
//Update the title of Read button
cell.readUnreadButtonLabel.text = "Read"
}
} else {
//handle close of the cell being edited already
if let previousEditedCell = tableView.cellForRow(at: indexPathBeingEdited!) as? NotificationCenterTableViewCell {
previousEditedCell.closeEditActions()
indexPathBeingEdited = nil
//Update the title of Read button
previousEditedCell.readUnreadButtonLabel.text = "Read"
}
}
}
}
}
In my table view cell:
func handleLeftSwipe(_ gestureRecognizer: UISwipeGestureRecognizer) {
if !isBeingEdited {
//Action to open the edit buttons
UIView.animate(withDuration: 0.5, animations: {
self.notificationHolderViewLeadingConstraint.constant -= 248
self.notificationHolderViewTrailingConstraint.constant -= 248
self.editActionsView.isHidden = false
self.layoutIfNeeded()
}, completion: { (success) in
})
isBeingEdited = true
}
}
func closeEditActions() {
if isBeingEdited {
//Action to open the edit buttons
UIView.animate(withDuration: 0.5, animations: {
self.notificationHolderViewLeadingConstraint.constant += 248
self.notificationHolderViewTrailingConstraint.constant += 248
self.editActionsView.isHidden = true
self.layoutIfNeeded()
}, completion: { (success) in
})
isBeingEdited = false
}
}
override func draw(_ rect: CGRect) {
if let viewToRound = editActionsView {
let path = UIBezierPath(roundedRect:viewToRound.bounds,
byRoundingCorners:[.topRight, .topLeft, .bottomRight, .bottomLeft],
cornerRadii: CGSize(width: 20, height: 20))
let maskLayer = CAShapeLayer()
maskLayer.path = path.cgPath
viewToRound.layer.mask = maskLayer
}
}
Just FYI, I have my edit buttons i.e., Read / View / Clear added to the editActionsView. The corresponding actions are hooked up with IBActions in my tableViewCell class.
The outcome is this:
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