ale00 ale00 - 3 months ago 13
Swift Question

Wrong frame values during animation

I want to make an animation like iOS home screen folder. I have a Container View in a Main View Controller and in the Container View I switch between two View Controllers with an animation.

Here is the code of Main View Controller Class:

class MainContainerViewController: UIViewController {

@IBOutlet weak var containerView: UIView!

let duration = 1.0
var presenting = true
var originFrame = CGRect.zero
var indexPathSelectedCell: IndexPath?

var dismissCompletion: (()->())?


func cycle(fromViewController: UIViewController, toViewController: UIViewController) {

let folderViewC = (presenting ? fromViewController : toViewController) as! ViewController
let projectViewC = (presenting ? toViewController : fromViewController) as! ProjectViewController

let cellView = (presenting ? (folderViewC.folderCollectionView.cellForItem(at: folderViewC.folderCollectionView.indexPathsForSelectedItems!.first!) as! FolderCollectionViewCell).folderView : projectViewC.containerView)!
let cellSnapshot = cellView.snapshotView(afterScreenUpdates: false)!
let cellFrame = containerView.convert(cellView.frame, from: cellView.superview)
cellSnapshot.frame = cellFrame
cellView.isHidden = true

toViewController.view.frame = self.containerView.frame
toViewController.view.layoutIfNeeded()
toViewController.view.alpha = 0


presenting ? (projectViewC.containerView.isHidden = true) : ((folderViewC.folderCollectionView.cellForItem(at: self.indexPathSelectedCell!) as! FolderCollectionViewCell).folderView.isHidden = true)

fromViewController.willMove(toParentViewController: nil)
self.addChildViewController(toViewController)
self.containerView.addSubview(toViewController.view)
self.containerView.addSubview(cellSnapshot)

UIView.animate(withDuration: duration, animations: {


toViewController.view.alpha = 1.0

let finalFrame = self.presenting ? projectViewC.containerView.frame : self.containerView.convert((folderViewC.folderCollectionView.cellForItem(at: self.indexPathSelectedCell!) as! FolderCollectionViewCell).folderView.frame, from: (folderViewC.folderCollectionView.cellForItem(at: self.indexPathSelectedCell!) as! FolderCollectionViewCell).folderView.superview)

cellSnapshot.frame = finalFrame
}) { (_) in

if !self.presenting {
self.dismissCompletion?()
}

self.presenting ? (projectViewC.containerView.isHidden = false) : ((folderViewC.folderCollectionView.cellForItem(at: self.indexPathSelectedCell!) as! FolderCollectionViewCell).folderView.isHidden = false)

cellSnapshot.removeFromSuperview()
fromViewController.view.removeFromSuperview()
fromViewController.removeFromParentViewController()
toViewController.didMove(toParentViewController: nil)

}

}

}


All the code works correctly except
let finalFrame = self.presenting ? projectViewC.containerView.frame : self.containerView.convert((folderViewC.folderCollectionView.cellForItem(at: self.indexPathSelectedCell!) as! FolderCollectionViewCell).folderView.frame, from: (folderViewC.folderCollectionView.cellForItem(at: self.indexPathSelectedCell!) as! FolderCollectionViewCell).folderView.superview)
that set
finalFrame
to a wrong value:


  • when it is presenting the Snapshot goes in the middle of the screen

  • when it is dismissing the Snapshot goes near his right position.



The
let finalFrame = self.presenting ? projectViewC.containerView.frame : self.containerView.convert((folderViewC.folderCollectionView.cellForItem(at: self.indexPathSelectedCell!) as! FolderCollectionViewCell).folderView.frame, from: (folderViewC.folderCollectionView.cellForItem(at: self.indexPathSelectedCell!) as! FolderCollectionViewCell).folderView.superview)
line works in this way:


  • check if it is presenting

  • if it is presenting set the constant to the frame value of the final folder view

  • if it is dismissing convert the frame value of the folderView of the selected Collection View Cell from the superview of this folderView



Here is the whole project: https://github.com/ale00/OnteamAnon

Answer

Since you're using auto layout for the size of your containerView in projectViewController, you need to call layoutIfNeeded() on self.containerView after this part of your code:

self.addChildViewController(toViewController)
self.containerView.addSubview(toViewController.view)
self.containerView.addSubview(cellSnapshot)

So it becomes:

self.addChildViewController(toViewController)
self.containerView.addSubview(toViewController.view)
self.containerView.addSubview(cellSnapshot)
self.containerView.layoutIfNeeded()