问题
I'm stuck in my project and is in need for some help. I want to push/present a UICollectionViewController
from a UICollectionViewCell
including my UINavigationBar
. I have understand that you can not actually present a ViewController from a Cell? How do I supposed to do in this case? My problem is that my NavigationBar won´t show up.
Here is my Cell:
import UIKit
import Firebase
class UserProfileHeader: UICollectionViewCell, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
lazy var followersLabelButton: UIButton = {
let button = UIButton(type: .system)
button.setTitle("followers", for: .normal)
button.setTitleColor(UIColor.lightGray, for: .normal)
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 14)
button.addTarget(self, action: #selector(followers), for: .touchUpInside)
return button
}()
@objc fileprivate func followers() {
let newController = NewController(collectionViewLayout: UICollectionViewFlowLayout())
self.window?.rootViewController?.present(newController, animated: true, completion: nil)
}
}
And the CollectionViewController:
import UIKit
import MapKit
import Firebase
class UserProfileController: UICollectionViewController, UICollectionViewDelegateFlowLayout, UIGestureRecognizerDelegate {
var userId: String?
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.backgroundColor = UIColor.white
collectionView?.register(UserProfileHeader.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "headerId")
}
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "headerId", for: indexPath) as! UserProfileHeader
header.user = self.user
return header
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width: view.frame.width, height: 200)
}
}
回答1:
1- Inside the cell
weak var delegate:UserProfileController?
2- Inside cellForItemAt
cell.delegate = self
3- Use this inside the cell
delegate?.present(newController, animated: true, completion: nil)
BTW i think you mean
delegate?.navigationController?.pushViewController(newController, animated: true)
回答2:
it`s not right way do this in view. Use MVC way: Move
button.addTarget(self, action: #selector(followers), for: .touchUpInside)
to UserProfileController in method
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "headerId", for: indexPath) as! UserProfileHeader as! UserProfileHeader
header.followersLabelButton.addTarget(self, action: #selector(followers), for: .touchUpInside)
header.user = self.user
return header
}
and rewrite
@objc func followers() {
let newController = self.navigationController
newController?.present(newController, animated: true, completion: nil)
}
回答3:
If you want to present a new ViewController you should create a new delegate in your Cell like this:
import UIKit
import Firebase
protocol CellDelegate {
func presentViewController()
}
class UserProfileHeader: UICollectionViewCell,
UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var delegate: CellDelegate?
lazy var followersLabelButton: UIButton = {
let button = UIButton(type: .system)
button.setTitle("followers", for: .normal)
button.setTitleColor(UIColor.lightGray, for: .normal)
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 14)
button.addTarget(self, action: #selector(followers), for: .touchUpInside)
return button
}()
@objc func followers() {
delegate.presentViewController
}
}
While in your ViewController you should make the delegate function works like this
import UIKit
import MapKit
import Firebase
class UserProfileController: UICollectionViewController, UICollectionViewDelegateFlowLayout, UIGestureRecognizerDelegate
, CellDelegate {
var userId: String?
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.backgroundColor = UIColor.white
collectionView?.register(UserProfileHeader.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "headerId")
}
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "headerId", for: indexPath) as! UserProfileHeader
header.user = self.user
// Remember to set the delegate for the cell
header.delegate = self
return header
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width: view.frame.width, height: 200)
}
func presentViewController() {
let newController = NewController(collectionViewLayout: UICollectionViewFlowLayout())
self.window?.rootViewController?.present(newController, animated: true, completion: nil)
}
}
回答4:
I really think you shouldn't be presenting from the cell at all, even if you have a reference to the viewController. I'd rather call a function on the delegate, and leave it to decide what to do -
import UIKit
import Firebase
protocol UserProfileHeaderDelegate: class {
func followersTapped()
}
class UserProfileHeader: UICollectionViewCell, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
weak var headerDelegate: UserProfileHeaderDelegate?
lazy var followersLabelButton: UIButton = {
let button = UIButton(type: .system)
button.setTitle("followers", for: .normal)
button.setTitleColor(UIColor.lightGray, for: .normal)
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 14)
button.addTarget(self, action: #selector(followers), for: .touchUpInside)
return button
}()
@objc fileprivate func followers() {
self.headerDelegate?.followersTapped()
}
}
In the viewController -
class UserProfileController: UICollectionViewController, UICollectionViewDelegateFlowLayout, UserProfileHeaderDelegate {
// etc, etc......
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "headerId", for: indexPath) as! UserProfileHeader
header.user = self.user
// Remember to set the delegate for the cell
header.headerDelegate = self
return header
}
// Implement the UserProfileHeaderDelegate protocol - this is called from within the cell
// so all the cell knows is that its delegate implements this protocol, which has the followersTapped() function
func followersTapped() {
let newController = NewController(collectionViewLayout: UICollectionViewFlowLayout())
self.present(newController, animated: true, completion: nil)
}
}
This way your viewController is not concerned with the inner workings of your cell, and vice-versa.
来源:https://stackoverflow.com/questions/53433399/swift-4-push-a-viewcontroller-from-a-uicollectionview-cell