UITableView cells animation on scroll. Swift - ios

Community, please help out a beginner! Can you tell me how to make such animation for TableView cells?
Thank!
cell animation as in this video with Swift

This gives something similar to what you want. You might need to make adjustments to it or improve the code snippet.
You can work with the panGestureRecognizer property of the tableView
tableView.panGestureRecognizer.addTarget(self, action: #selector(didPan(_:)))
With this handler:
#objc func didPan(_ gesture: UIPanGestureRecognizer) {
guard gesture.state == .changed else { return }
let loc = gesture.location(in: tableView)
guard let touchedCellIndex = tableView.indexPathForRow(at: loc) else { return }
let n = tableView.numberOfRows(inSection: 0)
guard touchedCellIndex.row < n - 1 else { return }
if gesture.translation(in: tableView).y < 0 {
for (index, cell) in tableView.visibleCells.enumerated() {
guard let ip = tableView.indexPath(for: cell) else { return }
if ip.row > touchedCellIndex.row {
cell.transform = CGAffineTransform(translationX: 0.0, y: -gesture.velocity(in: tableView).y * 0.02 * tanh(CGFloat(index)))
UIView.animate(withDuration: 0.05 * Double(index), delay: 0.0) {
cell.transform = CGAffineTransform.identity
}
}
}
} else {
for (index, cell) in tableView.visibleCells.reversed().enumerated() {
guard let ip = tableView.indexPath(for: cell) else { return }
if ip.row < touchedCellIndex.row {
cell.transform = CGAffineTransform(translationX: 0.0, y: -gesture.velocity(in: tableView).y * 0.02 * tanh(CGFloat(index)))
UIView.animate(withDuration: 0.05 * Double(index), delay: 0.0) {
cell.transform = CGAffineTransform.identity
}
}
}
}
}
I am sure you can optimize this approach and make it more concise.

Related

Drag & Drop Table view cell has weired buggy animation while dragging cell (Using long press gesture)

I'm following this to perform drag and drop table view cell but I don't know why I have buggy weird animation while dragging cell to other position in the table. I don't know what actually causes this type of issue, any help or suggestion would be appreciated. You can check the code and result below:
Code:
var longGesture: UILongPressGestureRecognizer!
var scrollRate: CGFloat = 0
var dragInitialIndexPath: IndexPath?
var dragCellSnapshot: UIView?
var scrollDisplayLink: CADisplayLink?
self.longGesture = UILongPressGestureRecognizer(target: self, action: #selector(onLongPressGesture(sender:)))
self.longGesture.minimumPressDuration = 0.3
self.tblEditProject.addGestureRecognizer(self.longGesture)
//MARK: tableCell reorder / long press
#objc func onLongPressGesture(sender: UILongPressGestureRecognizer) {
self.longGesture = sender
let state = sender.state
let locationInView = self.longGesture.location(in: self.tblEditProject)
let indexPath = self.tblEditProject.indexPathForRow(at: locationInView)
switch state {
case .began:
if indexPath != nil {
guard let currentIndexPath = indexPath else { return }
dragInitialIndexPath = currentIndexPath
self.scrollDisplayLink = CADisplayLink(target: self, selector: #selector(scrollTableWithCell))
self.scrollDisplayLink?.add(to: .main, forMode: .default)
guard let cell = self.tblEditProject.cellForRow(at: currentIndexPath) else { return }
dragCellSnapshot = self.snapshotOfCell(inputView: cell)
var center = cell.center
dragCellSnapshot?.center = center
dragCellSnapshot?.alpha = 0.0
self.tblEditProject.addSubview(dragCellSnapshot!)
UIView.animate(withDuration: 0.25, animations: { () -> Void in
center.y = locationInView.y
self.dragCellSnapshot?.center = center
self.dragCellSnapshot?.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
self.dragCellSnapshot?.alpha = 0.98
cell.alpha = 0.0
}, completion: { _ in
cell.isHidden = true
})
}
case .changed:
if indexPath != nil {
self.calculateScroll(gestureRecognizer: self.longGesture)
var center = dragCellSnapshot?.center
center?.y = locationInView.y
dragCellSnapshot?.center = center!
if indexPath != nil && indexPath != dragInitialIndexPath {
// update your data model
let dataToMove = self.arrEditProject[0].section[dragInitialIndexPath!.row]
self.arrEditProject[0].section.remove(at: dragInitialIndexPath!.row)
self.arrEditProject[0].section.insert(dataToMove, at: indexPath!.row)
self.tblEditProject.moveRow(at: dragInitialIndexPath!, to: indexPath!)
dragInitialIndexPath = indexPath
}
}
case .ended:
guard let persistedIndexPath = dragInitialIndexPath else { return }
guard let cell = self.tblEditProject.cellForRow(at: persistedIndexPath) else { return }
cell.isHidden = false
cell.alpha = 0.0
UIView.animate(withDuration: 0.25, animations: { () -> Void in
self.dragCellSnapshot?.center = cell.center
self.dragCellSnapshot?.transform = CGAffineTransform.identity
self.dragCellSnapshot?.alpha = 0.0
cell.alpha = 1.0
}, completion: { _ in
self.dragInitialIndexPath = nil
self.dragCellSnapshot?.removeFromSuperview()
self.dragCellSnapshot = nil
self.isUpdateContent = true
self.tblEditProject.reloadData()
/// For scrolling while dragging
self.scrollDisplayLink?.invalidate()
self.scrollDisplayLink = nil
self.scrollRate = 0
})
default:
guard let persistedIndexPath = dragInitialIndexPath else { return }
guard let cell = self.tblEditProject.cellForRow(at: persistedIndexPath) else { return }
cell.isHidden = false
cell.alpha = 0.0
UIView.animate(withDuration: 0.25) {
self.dragCellSnapshot?.center = cell.center
self.dragCellSnapshot?.transform = CGAffineTransform.identity
self.dragCellSnapshot?.alpha = 0.0
cell.alpha = 1.0
} completion: { _ in
self.dragInitialIndexPath = nil
self.dragCellSnapshot?.removeFromSuperview()
self.dragCellSnapshot = nil
}
}
}
func snapshotOfCell(inputView: UIView) -> UIView {
UIGraphicsBeginImageContextWithOptions(inputView.bounds.size, false, 0.0)
inputView.layer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
let cellSnapshot = UIImageView(image: image)
cellSnapshot.layer.masksToBounds = false
cellSnapshot.layer.cornerRadius = 0.0
cellSnapshot.layer.shadowOffset = CGSize(width: -5.0, height: 0.0)
cellSnapshot.layer.shadowRadius = 5.0
cellSnapshot.layer.shadowOpacity = 0.4
return cellSnapshot
}
func calculateScroll(gestureRecognizer: UIGestureRecognizer) {
print("Call scroll table with cell")
let location = gestureRecognizer.location(in: self.tblEditProject)
var rect: CGRect = self.tblEditProject.bounds
/// adjust rect for content inset as we will use it below for calculating scroll zones
rect.size.height -= self.tblEditProject.contentInset.top
/// tell us if we should scroll and which direction
let scrollZoneHeight = rect.size.height / 6
let bottomScrollBeginning = self.tblEditProject.contentOffset.y + self.tblEditProject.contentInset.top + rect.size.height - scrollZoneHeight
let topScrollBeginning = self.tblEditProject.contentOffset.y + self.tblEditProject.contentInset.top + scrollZoneHeight
/// we're in the bottom zone
if (location.y >= bottomScrollBeginning)
{
self.scrollRate = (location.y - bottomScrollBeginning) / scrollZoneHeight
}
/// we're in the top zone
else if (location.y <= topScrollBeginning)
{
self.scrollRate = (location.y - topScrollBeginning) / scrollZoneHeight
}
else
{
self.scrollRate = 0
}
}
#objc func scrollTableWithCell() {
print("Call scroll table with cell")
let gestureLong = self.longGesture
let location = gestureLong?.location(in: self.tblEditProject)
let currentOffset = self.tblEditProject.contentOffset
var newOffset = CGPoint(x: currentOffset.x, y: currentOffset.y + self.scrollRate * 10)
if (newOffset.y < -self.tblEditProject.contentInset.top) {
newOffset.y = -self.tblEditProject.contentInset.top
} else if (self.tblEditProject.contentSize.height + self.tblEditProject.contentInset.bottom < self.tblEditProject.frame.size.height) {
newOffset = currentOffset
} else if (newOffset.y > (self.tblEditProject.contentSize.height + self.tblEditProject.contentInset.bottom) - self.tblEditProject.frame.size.height) {
newOffset.y = (self.tblEditProject.contentSize.height + self.tblEditProject.contentInset.bottom) - self.tblEditProject.frame.size.height;
}
self.tblEditProject.setContentOffset(newOffset, animated: false)
if let lction = location {
if (lction.y >= 0 && lction.y <= self.tblEditProject.contentSize.height + 50) {
var center = dragCellSnapshot?.center
center?.y = lction.y
dragCellSnapshot?.center = center ?? CGPoint.zero
var indexPath = self.tblEditProject.indexPathForRow(at: lction)
/// Check if the pointer is bigger than the table height to set indexPath as the last cell
if (self.tblEditProject.contentSize.height < lction.y) {
indexPath = IndexPath(row: (self.tblEditProject.numberOfRows(inSection: 0)) - 1, section: 0)
}
if let pathIndex = indexPath {
if !pathIndex.isEmpty && pathIndex != dragInitialIndexPath {
// update your data model
let dataToMove = self.arrEditProject[0].section[dragInitialIndexPath!.row]
self.arrEditProject[0].section.remove(at: dragInitialIndexPath!.row)
self.arrEditProject[0].section.insert(dataToMove, at: pathIndex.row)
self.tblEditProject.moveRow(at: dragInitialIndexPath!, to: pathIndex)
dragInitialIndexPath = pathIndex
}
}
}
}
}
Result:
Apple's already performed Drag&Drop mechanism for UITableView and UICollectionView (Apple Documentation, How to use it). You don't need to develop it from scratch.

Swipe Gesture on UITableview Cell Like Whtsapp does for "Reply a Message"

How can we implement swipe gesture on tableview cell and move the tableview cell as the finger moves from left to right?
I am able to add the swipe gesture but moving the cell is something I want to implement.
Whatsapp has the same feature implemented while replying to a message and want to attain the same animation effect.
Any help will be appreciated.
Thanks
I have created a demo for this. You can use https://github.com/Dharmesh-shah2412/demoWhatsappSwipeToReply
Objective C :
I have added PanGesture to Tableviewcell :
- (nonnull UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath {
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"Cell"];
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:#selector(panGestureCellAction:)];
pan.delegate = self;
[cell.contentView addGestureRecognizer:pan];
return cell;
}
- (IBAction)panGestureCellAction:(UIPanGestureRecognizer *)recognizer {
CGPoint translation = [recognizer translationInView:self.view];
if (recognizer.view.frame.origin.x < 0) { return; }
recognizer.view.center = CGPointMake(recognizer.view.center.x+ translation.x,
recognizer.view.center.y );
[recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
if(recognizer.view.frame.origin.x > [UIScreen mainScreen].bounds.size.width * 0.9)
{
[UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
[recognizer.view setFrame: CGRectMake(0, recognizer.view.frame.origin.y, recognizer.view.frame.size.width, recognizer.view.frame.size.height)];
} completion:nil];
}
if (recognizer.state == UIGestureRecognizerStateEnded)
{
int x = recognizer.view.frame.origin.x;
[UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
[recognizer.view setFrame: CGRectMake(0, recognizer.view.frame.origin.y, recognizer.view.frame.size.width, recognizer.view.frame.size.height)];
} completion:^(BOOL finished) {
if (x > recognizer.view.frame.size.width / 2) {
[_txtField becomeFirstResponder];
}
}];
}
}
- (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)panGestureRecognizer {
CGPoint velocity = [panGestureRecognizer velocityInView:_tblView];
if (velocity.x < 0) {
return false;
}
return fabs(velocity.x) > fabs(velocity.y);
}
Swift :
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(panGestureCellAction))
cell.contentView.addGestureRecognizer(panGestureRecognizer)
return cell
}
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
let velocity : CGPoint = gestureRecognizer.location(in: tblView)
if velocity.x < 0 {
return false
}
return abs(Float(velocity.x)) > abs(Float(velocity.y))
}
#objc func panGestureCellAction(recognizer: UIPanGestureRecognizer) {
let translation = recognizer.translation(in: tblView)
if recognizer.view?.frame.origin.x ?? 0 < 0 {
return
}
recognizer.view?.center = CGPoint(
x: (recognizer.view?.center.x ?? 0) + translation.x,
y: (recognizer.view?.center.y ?? 0))
recognizer.setTranslation(CGPoint(x: 0, y: 0), in: view)
if (recognizer.view?.frame.origin.x ?? 0) > UIScreen.main.bounds.size.width * 0.9 {
UIView.animate(withDuration: 0.25, delay: 0, options: .curveEaseOut, animations: {
recognizer.view?.frame = CGRect(x: 0, y: recognizer.view?.frame.origin.y ?? 0, width: recognizer.view?.frame.size.width ?? 0, height: recognizer.view?.frame.size.height ?? 0)
})
}
if recognizer.state == .ended {
let x = recognizer.view?.frame.origin.x ?? 0
UIView.animate(withDuration: 0.25, delay: 0, options: .curveEaseOut) {
recognizer.view?.frame = CGRect(x: 0, y: recognizer.view?.frame.origin.y ?? 0, width: recognizer.view?.frame.size.width ?? 0, height: recognizer.view?.frame.size.height ?? 0)
} completion: { (finished) in
if x > ((recognizer.view?.frame.size.width ?? 0) / 2) {
self.txtChat.becomeFirstResponder()
}
}
}
}
I created the Swipe Gesture using swift 5 on Xcode 14.2
Following is my code in UITableViewCell to perform swiping...
//declare the `UISwipeGestureRecognizer`
let swipeGesture = UISwipeGestureRecognizer()
//a call back to notify the swipe in `cellForRowAt` as follow.
var replyCallBack : ( () -> Void)?
//this view perform swiping in cell
#IBOutlet weak var containerView: UIView!
override func awakeFromNib() {
super.awakeFromNib()
//set up your UI
setSwipeGesture() //register gesture
}
func setSwipeGesture(){
// Add the swipe gesture and set the direction to the right or left according to your needs
swipeGesture.direction = .right
contentView.addGestureRecognizer(swipeGesture)
// Add a target to the swipe gesture to handle the swipe
swipeGesture.addTarget(self, action: #selector(handleSwipe(_:)))
}
#objc func handleSwipe(_ gesture: UISwipeGestureRecognizer) {
// Animate the action view onto the screen when the user swipes right
if gesture.direction == .right {
UIView.animate(withDuration: 0.15) {
self.messageContainerView.transform = CGAffineTransform(translationX: self.contentView.frame.width / 2.5, y: 0)
// Schedule a timer to restore the cell after 0.2 seconds or change it according to your needs
Timer.scheduledTimer(withTimeInterval: 0.2, repeats: false) { (_) in
UIView.animate(withDuration: 0.1) {
self.messageContainerView.transform = .identity
//callback to notify in cellForRowAt
self.replyCallBack!()
//your code when
}
}
}
} else {
// Animate the action view off the screen when the user swipes left
UIView.animate(withDuration: 0.3) {
self.messageContainerView.transform = .identity
}
}
}
you can change the animation duration according to your need or .right to .left animation... in this case, I only performed the right swipe...

How to swap two cells of two different tables view?

I'm stuck with this problem:
I'm using this code to swap two cells of the same table view. I want to ask you how I should edit this code to swap two cells of two different table view in the same controller? I think that there isn't much to edit but I can't do on my own... thank you all.
#objc func onLongPressGestureDone(sender: UILongPressGestureRecognizer) {
let locationInView = sender.location(in: tableViewDone)
let indexPath = tableViewDone.indexPathForRow(at: locationInView)
if sender.state == .began {
if indexPath != nil {
initialIndexPathDone = indexPath
let cell = tableViewDone.cellForRow(at: indexPath!)
cellSnapshotDone = snapshotOfCellDone(inputView: cell!)
var center = cell?.center
cellSnapshotDone?.center = center!
cellSnapshotDone?.alpha = 0.0
tableViewDone.addSubview(cellSnapshotDone!)
UIView.animate(withDuration: 0.25, animations: { () -> Void in
center?.y = locationInView.y
self.cellSnapshotDone?.center = center!
self.cellSnapshotDone?.transform = (self.cellSnapshotDone?.transform.scaledBy(x: 1.05, y: 1.05))!
self.cellSnapshotDone?.alpha = 0.99
cell?.alpha = 0.0
}, completion: { (finished) -> Void in
if finished {
cell?.isHidden = true
}
})
}
} else if sender.state == .changed {
var center = cellSnapshotDone?.center
center?.y = locationInView.y
cellSnapshotDone?.center = center!
if ((indexPath != nil) && (indexPath != initialIndexPathDone)) {
progetto.done.swapAt(indexPath!.row, initialIndexPathDone!.row)
tableViewDone.moveRow(at: initialIndexPathDone!, to: indexPath!)
initialIndexPathDone = indexPath
}
} else if sender.state == .ended {
let cell = tableViewDone.cellForRow(at: initialIndexPathDone!)
cell?.isHidden = false
cell?.alpha = 0.0
UIView.animate(withDuration: 0.25, animations: { () -> Void in
self.cellSnapshotDone?.center = (cell?.center)!
self.cellSnapshotDone?.transform = CGAffineTransform.identity
self.cellSnapshotDone?.alpha = 0.0
cell?.alpha = 1.0
}, completion: { (finished) -> Void in
if finished {
self.initialIndexPathDone = nil
self.cellSnapshotDone?.removeFromSuperview()
self.cellSnapshotDone = nil
}
})
}
}
func snapshotOfCellDone(inputView: UIView) -> UIView {
UIGraphicsBeginImageContextWithOptions(inputView.bounds.size, false, 0.0)
inputView.layer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
let cellSnapshotDone = UIImageView(image: image)
cellSnapshotDone.layer.masksToBounds = false
cellSnapshotDone.layer.cornerRadius = 0.0
cellSnapshotDone.layer.shadowOffset = CGSize(width: -5.0, height: 0.0)
cellSnapshotDone.layer.shadowRadius = 5.0
cellSnapshotDone.layer.shadowOpacity = 0.4
return cellSnapshotDone
}
You can do this easier with the moveRow(at:to:) function:
tableView.beginUpdates()
tableView.moveRow(at: firstIndexPath, to: secondIndexPath)
tableView.moveRow(at: secondIndexPath, to: firstIndexPath)
tableView.endUpdates()

Dragging UIView

I need some help with dragging UIView to reveal, menu view underneath main view.
I have two UIViews.
menuView - includes menu buttons and labels
and mainView - located over menuView.
I want to drag the main view from left edge to show menu items and snap the main view to a specific position. I am able to get the dragging to the right working but I cannot set it back to original position when dragging left.
here is my codes I have been playing around with but no success.
I also wanted to make mainView smaller as I drag it to right.
any help will be greatly appreciated.
Note: PanGesture is attached to mainView.
#IBAction func dragMenu(_ sender: UIPanGestureRecognizer) {
let mview = sender.view!
let originalCenter = CGPoint(x: self.mainView.bounds.width/2, y: self.mainView.bounds.height/2)
switch sender.state {
case .changed:
if let mview = sender.view {
mview.center.x = mview.center.x + sender.translation(in: view).x
sender.setTranslation(CGPoint.zero, in: view)
}
case .ended:
let DraggedHalfWayRight = mview.center.x > view.center.x
if DraggedHalfWayRight {
//dragginToRight
showMenu = !showMenu
self.mainViewRight.constant = 200
self.mainTop.constant = 50
self.mainBottom.constant = 50
self.mainLeft.constant = 200
} else //dragging left and set it back to original position.
{
mview.center = originalCenter
showMenu = !showMenu
}
default:
break
}
}
I'd suggest a few things:
When you're done dragging the menu off, make sure to set its alpha to zero (so that, if you were in portrait and go to landscape, you don't suddenly see the menu sitting there).
I personally just adjust the transform of the dragged view and avoid resetting the translation of the gesture back to zero all the time. That's a matter of personal preference.
I'd make the view controller the delegate for the gesture and implement gestureRecognizerShouldBegin (because if the menu is hidden, you don't want to recognize swipes to try to hide it again; and if it's not hidden, you don't want to recognize swipes to show it).
When figuring out whether to complete the gesture or not, I also consider the velocity of the gesture (e.g. so a little flick will dismiss/show the animated view).
Thus:
class ViewController: UIViewController {
#IBOutlet weak var menuView: UIView!
var isMenuVisible = true
#IBAction func dragMenu(_ gesture: UIPanGestureRecognizer) {
let translationX = gesture.translation(in: gesture.view!).x
switch gesture.state {
case .began:
// if the menu is not visible, make sure it's off screen and then make it visible
if !isMenuVisible {
menuView.transform = CGAffineTransform(translationX: gesture.view!.bounds.width, y: 0)
menuView.alpha = 1
}
fallthrough
case .changed:
if isMenuVisible {
menuView.transform = CGAffineTransform(translationX: translationX, y: 0)
} else {
menuView.transform = CGAffineTransform(translationX: gesture.view!.bounds.width + translationX, y: 0)
}
case .ended:
let shouldComplete: Bool
if isMenuVisible {
shouldComplete = translationX > gesture.view!.bounds.width / 2 || gesture.velocity(in: gesture.view!).x > 0
} else {
shouldComplete = -translationX > gesture.view!.bounds.width / 2 || gesture.velocity(in: gesture.view!).x < 0
}
UIView.animate(withDuration: 0.25, animations: {
if self.isMenuVisible && shouldComplete || !self.isMenuVisible && !shouldComplete {
self.menuView.transform = CGAffineTransform(translationX: gesture.view!.bounds.width, y: 0)
} else {
self.menuView.transform = .identity
}
if shouldComplete{
self.isMenuVisible = !self.isMenuVisible
}
}, completion: { _ in
self.menuView.alpha = self.isMenuVisible ? 1 : 0
})
default:
break
}
}
}
extension ViewController: UIGestureRecognizerDelegate {
func gestureRecognizerShouldBegin(_ gesture: UIGestureRecognizer) -> Bool {
guard let gesture = gesture as? UIPanGestureRecognizer else { return true }
let translationX = gesture.translation(in: gesture.view!).x
return isMenuVisible && translationX > 0 || !isMenuVisible && translationX < 0
}
}
Personally, I prefer to use a separate screen edge gesture recognizer to pull them menu back on screen (you don't really want it to recognize gestures anywhere, but just on that right edge). Another virtue of this approach is that by keeping "show" and "hide" in different functions, the code is a lot more readable (IMHO):
class ViewController: UIViewController {
#IBOutlet weak var menuView: UIView!
var isMenuVisible = true
#IBAction func handleScreenEdgeGesture(_ gesture: UIScreenEdgePanGestureRecognizer) {
let translationX = gesture.translation(in: gesture.view!).x
switch gesture.state {
case .began:
menuView.transform = CGAffineTransform(translationX: gesture.view!.bounds.width, y: 0)
menuView.alpha = 1
fallthrough
case .changed:
menuView.transform = CGAffineTransform(translationX: gesture.view!.bounds.width + translationX, y: 0)
case .ended:
let shouldComplete = -translationX > gesture.view!.bounds.width / 2 || gesture.velocity(in: gesture.view!).x < 0
UIView.animate(withDuration: 0.25, delay:0, options: .curveEaseOut, animations: {
if shouldComplete {
self.menuView.transform = .identity
self.isMenuVisible = !self.isMenuVisible
} else {
self.menuView.transform = CGAffineTransform(translationX: gesture.view!.bounds.width, y: 0)
}
}, completion: { _ in
self.menuView.alpha = self.isMenuVisible ? 1 : 0
})
default:
break
}
}
#IBAction func dragMenu(_ gesture: UIPanGestureRecognizer) {
let translationX = gesture.translation(in: gesture.view!).x
switch gesture.state {
case .began, .changed:
menuView.transform = CGAffineTransform(translationX: translationX, y: 0)
case .ended:
let shouldComplete = translationX > gesture.view!.bounds.width / 2 || gesture.velocity(in: gesture.view!).x > 0
UIView.animate(withDuration: 0.25, delay:0, options: .curveEaseOut, animations: {
if shouldComplete {
self.menuView.transform = CGAffineTransform(translationX: gesture.view!.bounds.width, y: 0)
self.isMenuVisible = !self.isMenuVisible
} else {
self.menuView.transform = .identity
}
}, completion: { _ in
self.menuView.alpha = self.isMenuVisible ? 1 : 0
})
default:
break
}
}
}
extension ViewController: UIGestureRecognizerDelegate {
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
if gestureRecognizer is UIScreenEdgePanGestureRecognizer {
return !isMenuVisible
} else if let gesture = gestureRecognizer as? UIPanGestureRecognizer {
let translationX = gesture.translation(in: gesture.view!).x
return isMenuVisible && translationX > 0
}
return true
}
}

How to take screenshot of a uiview and drag in swift?

i got the code but its not working, let me know if im did anything wrong.
In the code i have a imageview which i created programmatically and adding the image into a uiview.Right now im unable to load the image in the "draggingView".
func longPressed(_ sender : UILongPressGestureRecognizer){
let locationInView = sender.location(in: self.view)
let cell = sender.view as? ParamterCollectionViewCell
var tImageView: UIImageView!
tImageView.frame = CGRect(x:0, y:0, width: 30 , height:30)
tImageView.image = parameterImageArray[0]
switch sender.state {
case .began:
// create an NSData object from myView
let archive = NSKeyedArchiver.archivedData(withRootObject: tImageView!)
// create a clone by unarchiving the NSData
draggingView = NSKeyedUnarchiver.unarchiveObject(with: archive) as? UIView
self.view.addSubview(draggingView!)
draggingView!.center = locationInView;
self.view.bringSubview(toFront: draggingView!)
break
case .changed:
if (contentView.frame.contains(locationInView)) {
draggingView?.center = locationInView;
}
break
case .ended:
break
default:
break
}
}
}
Give this a try... Very similar in idea to your code, but I think it might be a bit better of an approach:
func longPressed(_ sender : UILongPressGestureRecognizer) {
let locationInView: CGPoint = sender.location(in: self.view)
let locationInCollectionView: CGPoint = sender.location(in: self.collectionView)
if sender.state == .began {
if let indexPath: IndexPath = self.collectionView.indexPathForItem(at: locationInCollectionView) {
if let cell = self.collectionView.cellForItem(at: indexPath) {
UIGraphicsBeginImageContext(cell.bounds.size)
cell.layer.render(in: UIGraphicsGetCurrentContext()!)
let cellImage: UIImage? = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
self.movingCellImageView = UIImageView(image: cellImage)
self.movingCellImageView?.alpha = 0.75
self.view.addSubview(self.movingCellImageView!)
self.movingCellImageView?.center = locationInView
}
}
}
// Move movingCellImageView following finger position
if sender.state == .changed {
self.movingCellImageView?.center = locationInView
}
// Remove movingCellImageView when ended
if sender.state == .ended {
UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseOut, animations: {
self.movingCellImageView?.alpha = 0
}, completion: { (success: Bool) in
self.movingCellImageView?.removeFromSuperview()
self.movingCellImageView = nil
})
}
}
References:
Tim Puckett - https://adoptioncurve.net/archives/2014/07/creating-a-draggable-uicollectionviewcell/
Swift implementation by Chan Jing Hong
http://eatliftswift.weebly.com/technical/creating-a-draggable-uicollectionviewcell

Resources