簡體   English   中英

iOS Swift:如何重新創建照片應用程序UICollectionView布局

[英]iOS Swift: How to recreate a Photos App UICollectionView Layout

我想知道如何安靜一段時間如何創建iOS照片應用程序布局。 我怎樣才能使它看起來像放大到一個集合,同時導航欄顯示一個后退按鈕?

它是一個新的視圖控制器,它被推送到UINavigationController? 如果是這樣,他們在擴展時如何設法匹配瓷磚。

甚至可能有第三方庫讓我輕松地重新創建這樣的布局?

希望你能幫助我理解這是如何工作的概念。

回答你的第一個問題,“它是一個新的視圖控制器,它被推到UINavigationController上嗎?”。 是的,它是一個新的視圖控制器。 Apple在這里使用的是UIViewControllerTransitioningDelegate,它允許您呈現關於視圖控制器如何呈現和解除的自定義動畫。

現在關於第二個問題,“希望你能幫助我理解它是如何工作的概念。” 沒有簡單的方法來介紹它,因為涉及到很多。 我重新創建了我將在下面展示的效果,但首先我需要解釋一些核心原則。

來自Apple的文檔,

實現轉換委托對象時,可以返回不同的動畫對象,具體取決於視圖控制器是在呈現還是被解除。 所有轉換都使用轉換動畫對象 - 符合UIViewControllerAnimatedTransitioning協議的對象 - 來實現基本動畫。 過渡動畫制作者對象在有限的時間段內執行一組動畫。

換句話說,UIViewControllerTransitioningDelegate需要您創建的動畫對象,該對象描述應如何呈現視圖控制器以及如何將其解除。 這些代理方法中只有兩個對您想要實現的目標感興趣,它們是:

    func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
    let animator = PresentAnimator()
    return animator
}

這會要求您的代表在呈現視圖控制器時使用過渡動畫對象。

func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
    let animator = DismissAnimator()
    return animator
}

這將要求您的代理人在解除視圖控制器時使用過渡動畫對象。

PresentAnimator和DismissAnimator對象都符合UIViewControllerAnimatedTransitioning。 來自Apple的文檔:

在動畫對象中,實現transitionDuration(using :)方法以指定轉換的持續時間,並實現animateTransition(using :)方法自行創建動畫。 有關轉換中涉及的對象的信息將以上下文對象的形式傳遞給animateTransition(using :)方法。 使用該對象提供的信息在指定的持續時間內在屏幕上或屏幕外移動目標視圖控制器的視圖。

基本上,每個動畫制作者對象都將描述視圖控制器動畫的持續時間以及動畫的動畫方式。

現在這里展示了所有這些。 這就是我們將要實現的目標:

最終產品

在故事板中創建兩個視圖控制器。 我的第一個視圖控制器叫做ViewController,它包含一個Collection View和一個帶有標識符“MediaCell”的Collection View單元格和一個填充該集合視圖單元格的圖像。 集合視圖單元有一個名為ImageCollectionViewCell的類,只有這個:

    class ImageCollectionViewCell: UICollectionViewCell {

     @IBOutlet weak var image: UIImageView! //links to the collection view cell's image

     }

我的第二個視圖控制器叫做ImageRevealViewController,它只有一個圖像視圖和頂部的灰色視圖,我用來模擬導航欄和自定義后退按鈕(我用普通的UINavigationController導航欄嘗試了所有這些但是解雇動畫師無法工作。沒有任何羞恥的事情是制作看起來和行為像導航欄的東西雖然我只是為了演示)。

故事板

相冊

這將是您的ViewController的代碼。 基本上,這將是用戶找到照片集合的地方,就像相冊一樣。 你會看到我使用了兩個測試圖像。

    import UIKit

    class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {

@IBOutlet weak var collectionView: UICollectionView!

var selectedCell = UICollectionViewCell() //the selected cell, important for the animator

var media: [UIImage] = [UIImage]() //the photo album's images

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    media.append(UIImage(named: "testimage1")!)

    media.append(UIImage(named: "testimage2")!)

    collectionView.delegate = self

    collectionView.dataSource = self
}



func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

    selectedCell = collectionView.cellForItem(at: indexPath)!

    let selectedCellImage = selectedCell as! ImageCollectionViewCell

    let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)

    let imageRevealVC = mainStoryboard.instantiateViewController(withIdentifier: "ImageRevealVC") as! ImageRevealViewController

    imageRevealVC.transitioningDelegate = self

    imageRevealVC.imageToReveal = selectedCellImage.image.image

     /*
      This is where I tried using the nav controller but things did not work out for the dismiss animator. I have commented it out.
     */

    //let navController = UINavigationController(rootViewController: imageRevealVC)

    //navController.transitioningDelegate = self

    //navigationController?.pushViewController(imageRevealVC, animated: true)

    present(imageRevealVC, animated: true, completion: nil)

}

func numberOfSections(in collectionView: UICollectionView) -> Int {
    return 1
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

    return media.count

}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MediaCell", for: indexPath) as! ImageCollectionViewCell

    cell.image.image = media[indexPath.row]

    cell.image.contentMode = .scaleAspectFill

    return cell
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    let itemsPerRow:CGFloat = 3
    let hardCodedPadding:CGFloat = 2
    let itemWidth = (collectionView.bounds.width / itemsPerRow) - hardCodedPadding
    let itemHeight = itemWidth
    return CGSize(width: itemWidth, height: itemHeight)
}




 }

    extension ViewController: UIViewControllerTransitioningDelegate {

func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
    let animator = PresentAnimator()
    animator.originFrame = selectedCell.frame //the selected cell gives us the frame origin for the reveal animation
    return animator
}

func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
    let animator = DismissAnimator()
    return animator
}




 }

UIViewControllerTransitioningDelegate與我談到的動畫師對象一起結束。 請注意,在集合視圖的didSelect中,我實例化了新的視圖控制器並使其轉換委托等於self。

動畫師

制作動畫師總是有三個步驟。

  1. 設置過渡
  2. 創建動畫
  3. 完成過渡

現在為現在的動畫師。 創建一個名為PresentAnimator的新Swift類並添加以下內容:

    import Foundation

     import UIKit

   class PresentAnimator: NSObject, UIViewControllerAnimatedTransitioning {

let duration = 0.5

var originFrame = CGRect.zero

func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
    return duration
}


func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {

    let containerView = transitionContext.containerView


    let toView = transitionContext.view(forKey: UITransitionContextViewKey.to)!


    //2) create animation
    let finalFrame = toView.frame

    let xScaleFactor = originFrame.width / finalFrame.width
    let yScaleFactor = originFrame.height / finalFrame.height

    let scaleTransform = CGAffineTransform(scaleX: xScaleFactor, y: yScaleFactor)

    toView.transform = scaleTransform
    toView.center = CGPoint(
        x: originFrame.midX,
        y: originFrame.midY
    )

    toView.clipsToBounds = true



    containerView.addSubview(toView)


    UIView.animate(withDuration: duration, delay: 0.0,
                   options: [], animations: {

                    toView.transform = CGAffineTransform.identity
                    toView.center = CGPoint(
                        x: finalFrame.midX,
                        y: finalFrame.midY
                    )

    }, completion: {_ in

        //3 complete the transition
        transitionContext.completeTransition(
            !transitionContext.transitionWasCancelled
        )
    })

}

   }

現在為Dismiss Animator。 創建一個名為DismissAnimator的新類並添加以下內容:

    import Foundation

    import UIKit

    class DismissAnimator: NSObject, UIViewControllerAnimatedTransitioning {

let duration = 0.5

func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
    return duration
}

func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {

    //1) setup the transition
    let containerView = transitionContext.containerView

    let fromView = transitionContext.view(forKey: UITransitionContextViewKey.from)!
    let toView = transitionContext.view(forKey: UITransitionContextViewKey.to)!

    containerView.insertSubview(toView, belowSubview: fromView)

    //2) animations!

    UIView.animate(withDuration: duration, delay: 0.0, options: [], animations: {

        fromView.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)

    }, completion: {_ in

        //3) complete the transition
        transitionContext.completeTransition(
            !transitionContext.transitionWasCancelled
        )
    })


}

    }

圖像顯示

現在為最后一步,顯示圖像的視圖控制器。 在你的ImageRevealController中添加:

    import UIKit

    class ImageRevealViewController: UIViewController {

    var imageToReveal: UIImage!

@IBOutlet weak var imageRevealed: UIImageView!

override func viewDidLoad() {
    super.viewDidLoad()

    imageRevealed.image = imageToReveal



}


@IBAction func backButton(_ sender: Any) {

    dismiss(animated: true, completion: nil)

}

  }

backButton連接到我添加到視圖的按鈕,其作用類似於導航欄。 您可以添加自己的后退指示燈,使其更加真實。

有關UIViewControllerTransitioningDelegate的更多信息,這里有一個部分“From View Controller”使用UIViewControllerContextTransitioning消失 ,您可以查看並向我提供了答案。

要創建照片庫,請參閱: https//github.com/inspace-io/INSPhotoGallery

它是一個很好的圖書館,可以顯示照片,縮放功能等等。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM