Skip to content

Latest commit

 

History

History
151 lines (116 loc) · 6.3 KB

File metadata and controls

151 lines (116 loc) · 6.3 KB

SDECollectionViewAlbumTransition

UICollectionViewController Transition like open and close an album. Blog for this: Part I, Part II

AlbumTransition

Installtion

Drag files in "Classes" folder into your project.

Usage

  • In your storyboard, drag a object to your navigation controller, and set its custom class to "SDENavigationControllerDelegate"

drag an Object and set the custom class

  • Set this object to be your navigation controller's delegate.

set the delegate

  • At the last, add several lines code in your UICollectionView's delegate:

      override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
          self.selectedIndexPath = indexPath
          let layoutAttributes = self.collectionView!.layoutAttributesForItemAtIndexPath(indexPath)
          let areaRect = self.collectionView!.convertRect(layoutAttributes!.frame, toView: self.collectionView!.superview)
          let toVC = ......
          toVC.coverRectInSuperview = areaRect
          ...
      }
    

Now your project supports to pinch to pop.

Requirements

  • iOS 8.0+
  • Swift 2.0

Thanks for @CezaryKopacz, @ColinEberhardt. I learn a lot from their repo. And thanks for Vincent Ngo very much, I find the key to resolve the problem of pinching to push. There is a little problem with time delta algorithm, I will update if I find the way to improvement.

Pinch to push?

Pinching to push is a little complex. ViewController to push must be created before push, and init a ViewController is complex than do something to a existed ViewController, so this is why most of libraries do not support pinch to push.

If you want to support pinch to push, switch to the branch "Pinch-Push-Pop-Transition", drag files in "Classes" folder in this branch into your project, there is a little difference between "Pinch-Push-Pop-Transition" branch with other branches.

Add the below properties to your UICollectionViewController child class:

var transitionDelegate: SDENavigationControllerDelegate?
var pinchGestureRecognizer: UIPinchGestureRecognizer?{
    didSet(newValue){
        collectionView?.addGestureRecognizer(pinchGestureRecognizer!)
    }
}

override viewDidLoad(){
    ...
    pinchGestureRecognizer = UIPinchGestureRecognizer(target: self, action: "handlePinch:")
}

deinit{
    if pinchGestureRecognizer != nil{
        collectionView?.removeGestureRecognizer(pinchGestureRecognizer!)
    }
}

//MARK: Pinch Push and Pop
func getIndexPathForGesture(gesture: UIPinchGestureRecognizer) -> NSIndexPath?{
    let location0 = gesture.locationOfTouch(0, inView: gesture.view)
    let location1 = gesture.locationOfTouch(1, inView: gesture.view)
    let middleLocation = CGPointMake((location0.x + location1.x)/2, (location0.y + location1.y)/2)
    let indexPath = collectionView?.indexPathForItemAtPoint(middleLocation)
    return indexPath
}

func handlePinch(gesture: UIPinchGestureRecognizer){
    switch gesture.state{
    case .Began:
        if gesture.scale >= 1.0{
            guard let indexPath = getIndexPathForGesture(gesture) else{
                return
            }

            self.selectedIndexPath = indexPath
            let layoutAttributes = collectionView!.layoutAttributesForItemAtIndexPath(indexPath)
            let areaRect = collectionView!.convertRect(layoutAttributes!.frame, toView: collectionView?.superview)

            if let toVC = ...{
                toVC.coverRectInSuperview = areaRect

                transitionDelegate = navigationController?.delegate as? SDENavigationControllerDelegate
                transitionDelegate?.interactive = true
                navigationController?.pushViewController(toVC, animated: true)
            }

        }else{
            //after view controller is poped, UIViewController.navigationController is nil. So you need to keep it somewhere before pop
            transitionDelegate = self.navigationController?.delegate as? SDENavigationControllerDelegate
            transitionDelegate?.interactive = true
            self.navigationController?.popViewControllerAnimated(true)
        }

    case .Changed:
        guard transitionDelegate != nil else{
            return
        }
        guard let interactionController = transitionDelegate?.interactionController else{
            return
        }

        var progress = gesture.scale
        if transitionDelegate!.isPush{
            progress = gesture.scale - 1.0 >= 0.9 ? 0.9 : gesture.scale - 1.0
        }else{
            progress = 1.0 - gesture.scale
        }

        interactionController.updateInteractiveTransition(progress)
    case .Ended, .Cancelled:
        guard transitionDelegate != nil else{
            return
        }
        guard let interactionController = transitionDelegate?.interactionController else{
            return
        }

        var progress = gesture.scale
        if transitionDelegate!.isPush{
            progress = gesture.scale - 1.0 >= 0.9 ? 0.9 : gesture.scale - 1.0
        }else{
            progress = 1.0 - gesture.scale
        }

        if progress >= 0.4{
            interactionController.finishInteractiveTransition()
        }else{
            interactionController.cancelInteractiveTransition()
        }
        transitionDelegate?.interactive = false
    default:
        guard transitionDelegate != nil else{
            return
        }
        transitionDelegate?.interactive = false
    }
}