Reputation: 305
I am doing everything programatically, avoiding storyboards. I have a collectionView, a Post
model object that holds a username and password and of course I have collectionView cells. I the issue I am having is that I have a button inside of my collectionView Cells. I want to be able to tap this button and segue into a new controller. This is the easy part. The problem is that I want to not only segue into the new controller but also pass in the specific username of that specific Post Cell of the button I tapped. I hope this makes sense. Basically I want to have a Post, just like any social media application and I want to segue to a "profile" and also pass in the username of that specific user to that profile controller too. I hope you can understand this. Any help will be highly, highly appreciated as I have been stuck on this for some time. I will of course mark as answer. Thank you guys...
class MyController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
var posts = [Post]()
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.backgroundColor = .white
collectionView?.register(CustomCell.self, forCellWithReuseIdentifier: "cellId")
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return posts.count
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: 50)
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! CustomCell
cell.post = posts[indexPath.item]
cell.homeController = self
return cell
}
class CustomCell: UICollectionViewCell, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
var homeController: MyController?
var post: Post? {
didSet {
if let username = post?.username {
usernameLabel.text = username
}
}
}
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .blue
setupViews()
}
lazy var myButton: UIButton = {
let btn = UIButton()
btn.backgroundColor = .red
btn.setTitle("Push", for: .normal)
btn.isUserInteractionEnabled = false
btn.addTarget(self, action: #selector(handleTapped), for: .touchUpInside)
return btn
}()
let usernameLabel: UILabel = {
let label = UILabel()
label.textColor = .white
return label
}()
func handleTapped() {
let postController = PostController()
homeController?.navigationController?.pushViewController(postController, animated: true)
}
func setupViews() {
addSubview(myButton)
myButton.frame = CGRect(x: (self.frame.width / 2) - 25, y: (self.frame.height / 2) - 25, width: 50, height: 50)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Upvotes: 2
Views: 2395
Reputation: 3278
I suggest that you to tell your UIViewController
that a button inside your CustomCell
has been clicked. You can add a protocol, add a delegate
property to your cell and then MyController
has to conform to the protocol. The function should also pass in the cell that has been clicked and you can get the indexPath
of that cell from your collectionView
.
protocol CustomCellDelegate: class {
func didSelectButton(in cell: CustomCell)
}
class CustomClass: UICollectionViewClass {
weak var delegate: CustomCelLDelegate?
func handleTapped() {
delegate?.didSelectButton(in: self)
}
}
Then in your MyController
class, add the delegate and conform to the protocol.
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! CustomCell
cell.post = posts[indexPath.item]
cell.delegate = self
return cell
}
extension MyController: CustomCellDelegate {
func didSelectButton(in cell: CustomCell) {
if let indexPath = collectionView.indexPath(for: cell) {
let postController = PostController()
let post = posts[indexPath.row]
postController.post = post //pass the data
self.navigationController?.pushViewController(postController, animated: true)
}
}
}
You also need to add a post
variable to your PostController
.
class PostController {
var post: Post!
}
Upvotes: 5
Reputation: 72460
You are not using the segue instead of that you have pushed the ViewController using the navigationController
. So pass the value with the postController
object.
func handleTapped() {
let postController = PostController()
//Pass the detail that you want
postController.selectedPost = self.post
homeController?.navigationController?.pushViewController(postController, animated: true)
}
Now in PostController
declare one instance property of type Post
with name selectedPost
and then use that object in viewDidLoad
to assign your Labels
.
class PostController: UIViewController {
var selectedPost: Post?
override viewDidLoad() {
super.viewDidLoad()
self.yourLabel.text = self.selectedPost.username
}
Upvotes: 2