[英]How to select ALL UICollectionView cells like in the iOS Photos app using Swift?
[英]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。
動畫師
制作動畫師總是有三個步驟。
現在為現在的動畫師。 創建一個名為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.