所以,我在TableViewCell中有一个CollectionView,当有人点击单元格时,我想将该嵌入的Collection视图的单元格视图传递给ViewControllerAnimatedTransioning。我的问题是,当你单击单元格时我将indexPath保存在var中,所以当我在转换中执行委托时我可以检索那个单元格,那就是委托工作正常但是它返回nil。我有几个小时试图弄明白,而且我真的不知道发生了什么。我不知道它是否是实例的问题,但它不起作用。我把代码留给了你。我试图传递的单元格在ForYouCell中。
HomeCellTransition
import UIKit
protocol HomeCellTransitionDelegate {
func transition(for: HomeCellTransition) -> UIView!
}
class HomeCellTransition: NSObject, UIViewControllerAnimatedTransitioning {
enum TransitionType {
case presenting
case dismissing
case none
}
enum TransitionState {
case initial
case final
}
let duration: TimeInterval = 0.8
var type: TransitionType = .none
var topSnapshot: UIView!
var cellSnapshot: UIView!
var bottomSnapshot: UIView!
var secondViewTopSnapshot: UIView!
var secondViewBottomSnapshot: UIView!
var delegate: HomeCellTransitionDelegate = ForYouCell()
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return duration
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
guard let toVC = transitionContext.viewController(forKey: .to), let fromVC = transitionContext.viewController(forKey: .from) else {
return
}
let containerView = transitionContext.containerView
let presentingViewController = type == .presenting ? fromVC : toVC
let dismissingViewController = type == .presenting ? toVC : fromVC
let cellView = delegate.transition(for: self)
let targetFrame = cellView?.convert((cellView?.frame)!, to: cellView?.superview)
let percentCutImage: CGFloat = 0.10
let secondImageView = (dismissingViewController as! DetailController).topImage
snapshotViews(presentingVC: presentingViewController, dismissingVC: dismissingViewController, cellView: cellView!, targetFrame: targetFrame!, percentCutImage: percentCutImage, secondImageView: secondImageView)
containerView.addSubview(toVC.view)
containerView.addSubview(topSnapshot)
containerView.addSubview(cellSnapshot)
containerView.addSubview(bottomSnapshot)
containerView.addSubview(secondViewTopSnapshot)
containerView.addSubview(secondViewBottomSnapshot)
toVC.view.isHidden = true
topSnapshot.frame = CGRect.init(x: 0, y: 0, width: (presentingViewController.view.frame.width), height: (targetFrame?.minY)!)
cellSnapshot.frame = CGRect.init(x: 0, y: 0, width: (cellView?.frame.width)!, height: (cellView?.frame.height)! - ((cellView?.frame.height)! * percentCutImage))
bottomSnapshot.frame = CGRect.init(x: 0, y: targetFrame!.maxY, width: (presentingViewController.view.frame.width), height: (presentingViewController.view.frame.height) - (targetFrame?.maxY)!)
UIView.animate(withDuration: duration, animations: {
self.topSnapshot.frame.size.height = 0
self.bottomSnapshot.frame.origin.y = 0
self.cellSnapshot.frame = secondImageView.frame
}) { (completed) in
print("completed")
}
}
func snapshotViews(presentingVC: UIViewController, dismissingVC: UIViewController, cellView: UIView, targetFrame: CGRect, percentCutImage: CGFloat, secondImageView: UIImageView) {
let presentingView = presentingVC.view
let dismissingView = dismissingVC.view
let percentCutImage: CGFloat = percentCutImage
let secondImageView = secondImageView
let targetFrame = targetFrame
topSnapshot = presentingView?.resizableSnapshotView(from: CGRect.init(x: 0, y: 0, width: (presentingView?.frame.width)!, height: targetFrame.minY), afterScreenUpdates: false, withCapInsets: .zero)
cellSnapshot = cellView.resizableSnapshotView(from: CGRect.init(x: 0, y: 0, width: cellView.frame.width, height: cellView.frame.height - (cellView.frame.height * percentCutImage)), afterScreenUpdates: false, withCapInsets: .zero)
bottomSnapshot = presentingView?.resizableSnapshotView(from: CGRect.init(x: 0, y: targetFrame.maxY, width: (presentingView?.frame.width)!, height: (presentingView?.frame.height)! - targetFrame.maxY), afterScreenUpdates: false, withCapInsets: .zero)
secondViewTopSnapshot = dismissingView?.resizableSnapshotView(from: CGRect.init(x: 0, y: 0, width: (dismissingView?.frame.width)!, height: secondImageView.frame.height - (secondImageView.frame.height * percentCutImage)), afterScreenUpdates: true, withCapInsets: .zero)
secondViewBottomSnapshot = dismissingView?.resizableSnapshotView(from: CGRect.init(x: 0, y: secondImageView.frame.maxY - (secondImageView.frame.height * percentCutImage), width: (dismissingView?.frame.width)!, height: (dismissingView?.frame.height)! - (secondImageView.frame.height - (secondImageView.frame.height * percentCutImage))), afterScreenUpdates: true, withCapInsets: .zero)
}
}
extension HomeCellTransition: UIViewControllerTransitioningDelegate {
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
type = .presenting
return self
}
}
ForYouCell
//
// ForYouCell.swift
// AirbnbNav
//
// Created by Leonardo Dominguez on 9/24/17.
// Copyright © 2017 Leonardo Dominguez. All rights reserved.
//
import UIKit
protocol HeaderControllerPresentDelegate {
func didSelectCell()
}
class ForYouCell: UITableViewCell {
let cellIdentifier = "forYouCell"
var delegate: HeaderControllerPresentDelegate?
let itemsInsets: CGFloat = 15
var selectedCell: IndexPath?
let sectionLabel: UILabel = {
let lbl = UILabel()
lbl.text = "Section"
lbl.font = UIFont.boldSystemFont(ofSize: 14)
return lbl
}()
let collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = .white
return cv
}()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
collectionView.register(ItemCell.self, forCellWithReuseIdentifier: cellIdentifier)
collectionView.delegate = self
collectionView.dataSource = self
collectionView.contentInset = UIEdgeInsets(top: 0, left: itemsInsets, bottom: 0, right: itemsInsets)
setupViews()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupViews() {
addSubview(sectionLabel)
addSubview(collectionView)
_ = sectionLabel.anchor(top: topAnchor, bottom: nil, right: rightAnchor, left: leftAnchor, topConstant: 0, bottomConstant: 0, rightConstant: 0, leftConstant: itemsInsets, widthConstant: 0, heightConstant: 30)
_ = collectionView.anchor(top: sectionLabel.bottomAnchor, bottom: bottomAnchor, right: rightAnchor, left: leftAnchor, topConstant: 0, bottomConstant: 0, rightConstant: 0, leftConstant: 0, widthConstant: 0, heightConstant: 0)
}
}
extension ForYouCell: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellIdentifier, for: indexPath) as? ItemCell {
cell.backgroundColor = .red
return cell
}
return UICollectionViewCell()
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
selectedCell = indexPath
delegate?.didSelectCell()
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.size.height + 50, height: collectionView.frame.size.height - 20)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 15
}
}
extension ForYouCell: HomeCellTransitionDelegate {
func transition(for: HomeCellTransition) -> UIView! {
let celll = collectionView.cellForItem(at: selectedCell!)
print(celll)
print("k")
return celll
}
}
HeaderController
//
// HeaderController.swift
// AirbnbNav
//
// Created by Leonardo Dominguez on 9/19/17.
// Copyright © 2017 Leonardo Dominguez. All rights reserved.
//
import UIKit
enum HeaderSizes {
case min
case med
case max
}
protocol HeaderControllerDelegate {
func didCollapse()
func didExpand()
}
class HeaderController: UIViewController {
// Status bar
var isHiddenStatusBar: Bool = false {
didSet {
UIView.animate(withDuration: 0.3) {
self.setNeedsStatusBarAppearanceUpdate()
}
}
}
override var prefersStatusBarHidden: Bool {
return isHiddenStatusBar
}
override var preferredStatusBarStyle: UIStatusBarStyle {
if currentHeaderSize == .min {
return .default
}
return .lightContent
}
override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation {
return .fade
}
// Properties
let tableView: UITableView = {
let tv = UITableView(frame: .zero)
tv.separatorStyle = .none
return tv
}()
let maxHeight: CGFloat = 300
let medHeight: CGFloat = 135 // 55 del height + 10 padding superior + 10 de padding inferior + 10 statusbar
let minHeight: CGFloat = 65 // 55 height del menu + 10 padding
var previousScroll: CGFloat = 0
var currentHeaderSize: HeaderSizes = .max
var currentHeaderHeight: NSLayoutConstraint?
fileprivate let cellIdentifier = "cellIdentifier"
let detailController = DetailController()
var selectedCell: UITableViewCell?
lazy var headerView: HeaderView = {
let hv = HeaderView(maxHeight: self.maxHeight, medHeight: self.medHeight, minHeight: self.minHeight, paddingBetween: 10)
return hv
}()
override func viewDidLoad() {
super.viewDidLoad()
setupViews()
tableView.delegate = self
tableView.dataSource = self
tableView.register(ForYouCell.self, forCellReuseIdentifier: cellIdentifier)
headerView.headerControllerDelegate = self
}
func setupViews() {
view.addSubview(headerView)
view.addSubview(tableView)
currentHeaderHeight = headerView.anchor(top: view.topAnchor, bottom: nil, right: view.rightAnchor, left: view.leftAnchor, topConstant: 0, bottomConstant: 0, rightConstant: 0, leftConstant: 0, widthConstant: 0, heightConstant: maxHeight)[3]
_ = tableView.anchor(top: headerView.bottomAnchor, bottom: view.bottomAnchor, right: view.rightAnchor, left: view.leftAnchor)
}
}
extension HeaderController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? ForYouCell {
cell.delegate = self
return cell
}
return UITableViewCell()
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 250
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let absoluteTop: CGFloat = 0
let absoluteBottom: CGFloat = scrollView.contentSize.height - scrollView.frame.height
let scrollRange: CGFloat = scrollView.contentOffset.y - previousScroll
let isScrollingDown = scrollView.contentOffset.y > previousScroll && scrollView.contentOffset.y > absoluteTop
let isScrollingUp = scrollView.contentOffset.y < previousScroll && scrollView.contentOffset.y < absoluteBottom
var newHeight: CGFloat = currentHeaderHeight!.constant
if isScrollingDown {
newHeight = max(minHeight, ((currentHeaderHeight?.constant)! - abs(scrollRange)))
} else if isScrollingUp {
newHeight = min(maxHeight, ((currentHeaderHeight?.constant)! + abs(scrollRange)))
}
if newHeight != currentHeaderHeight?.constant {
currentHeaderHeight?.constant = newHeight
tableView.contentOffset = CGPoint(x: tableView.contentOffset.x, y: previousScroll)
let minMedAverage: CGFloat = (minHeight + medHeight) / 2
let medMaxAverage: CGFloat = (medHeight + maxHeight) / 2
if currentHeaderHeight!.constant < minMedAverage {
currentHeaderSize = .min
} else if currentHeaderHeight!.constant >= minMedAverage && currentHeaderHeight!.constant < medMaxAverage {
currentHeaderSize = .med
} else if currentHeaderHeight!.constant >= medMaxAverage {
currentHeaderSize = .max
}
updateHeader()
}
previousScroll = scrollView.contentOffset.y
}
func snapHeader(toSize: HeaderSizes) {
switch toSize {
case .max:
currentHeaderHeight?.constant = maxHeight
case .med:
currentHeaderHeight?.constant = medHeight
case .min:
currentHeaderHeight?.constant = minHeight
}
UIView.animate(withDuration: 0.3) {
self.view.layoutIfNeeded()
}
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
snapHeader(toSize: currentHeaderSize)
updateHeader()
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if !decelerate {
snapHeader(toSize: currentHeaderSize)
updateHeader()
}
}
func updateHeader() {
let range = maxHeight - medHeight
let percent = (currentHeaderHeight!.constant - medHeight) / range
headerView.updateHeader(percentage: percent, currentHeaderHeight: currentHeaderHeight!.constant)
// Status bar
isHiddenStatusBar = currentHeaderHeight!.constant < (medHeight / 2) && currentHeaderHeight!.constant > minHeight ? true : false
}
}
extension HeaderController: HeaderControllerPresentDelegate {
func didSelectCell() {
present(detailController, animated: true, completion: nil)
}
}
extension HeaderController: HeaderControllerDelegate {
func didExpand() {
print("")
}
func didCollapse() {
snapHeader(toSize: .min)
}
}