Swift: How to use “didSelectItemAtIndexPath” in UI

2019-02-19 06:33发布

I have a UITableViewController, inside the TableViewCell, it's a UICollectionView. I want to pass the data from the CollectionViewCell to a DetailViewController when user tapped the cell. I dragged a segue from the CollectionViewCell to the DetailViewController, and used the "didSelectItemAtIndexPath" inside the TableViewCell( which contains CollectionView), and it works.

class TableViewCell: UITableViewCell, UICollectionViewDataSource, UICollectionViewDelegate {

var posts1: [Posts] = [Posts]()
var posts2: [Posts] = [Posts]()
var categories: [Category] = [Category]()
var selectedPost1: Posts?

@IBOutlet weak var theCollectionView: UICollectionView!


func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return posts1.count

}

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
    let collectionViewCell = collectionView.dequeueReusableCellWithReuseIdentifier("CollectionViewCell", forIndexPath: indexPath) as! CollectionViewCell

        let imageUrlString: String = posts1[indexPath.row].postThumbnailUrlString
        let imageUrl: NSURL = NSURL(string: imageUrlString)!
    //Give Images A round cornor

    let filter = AspectScaledToFillSizeWithRoundedCornersFilter(
        size: collectionViewCell.postImageView.frame.size,
        radius: 20.0
    )

    collectionViewCell.postImageView.af_setImageWithURL(imageUrl, filter: filter)

    collectionViewCell.postTitleLabel.text = posts1[indexPath.row].postTite
return collectionViewCell
}

func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
    print("selected")
    self.selectedPost1 = self.posts1[indexPath.row]
}

it can print "selected" which means the data have already been stored in "self.selectedPost1". But I can't use "prepareForSegue" inside this class, since it can only be used in ViewController. someone told me to implement "UICollectionViewDelegate" in my "HomeTableViewController", and call the function "didSelectedItemAtIndexPath" in the HomeTableViewController, like this:

import UIKit

class HomePageTableViewController: UITableViewController,UICollectionViewDelegate {
    let sections: NSArray = ["latest news", "good news"]
    var posts1: [Posts] = [Posts]()
    var selectedIndexPath: NSIndexPath?

override func viewDidLoad() {
    super.viewDidLoad()


}

override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
  if section < sections.count{
        return sections[section] as? String
    }

    return nil

}

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return sections.count
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

    return 1
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    if indexPath.row == 0 && indexPath.section == 0 {
        let tableViewCell = tableView.dequeueReusableCellWithIdentifier("TableViewCell") as! TableViewCell

        tableViewCell.getCategories()
     //   tableViewCell.scrollToNextCell()
     //   tableViewCell.startTimer()


        return tableViewCell

    }
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
    self.performSegueWithIdentifier("goToDetail", sender: TableViewCell())
    print("selected")
}

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if let tableViewCell1 = sender as? TableViewCell,
    let postDetailPage = segue.destinationViewController as? DetailViewController{

        let selectedPosts = tableViewCell1.selectedPost1

        postDetailPage.selectedPost?.selectedPost1 = selectedPosts

}

However, the "didSelectedItemAtIndexPath" can't be called, there is no print. I don't know why?

here is my DetailViewController:

import UIKit

class DetailViewController: UIViewController {
@IBOutlet weak var postImageView: UIImageView!

var posts: [Posts] = [Posts]()
var selectedPost: TableViewCell?

override func viewDidLoad() {
    super.viewDidLoad()

    if let post = selectedPost?.selectedPost1{
        let thumbnailUrlString = post.postThumbnailUrlString
        let imageUrl: NSURL = NSURL(string: thumbnailUrlString)!
        print(thumbnailUrlString)
        postImageView.af_setImageWithURL(imageUrl)
    }
}

and also do I need to implement in viewDidLoad or viewDidAppear?

I have been struggled in this problem for few days? need some suggestions on How to do Segue from a UICollectionViewCell (which is inside a UITableViewCell) to a new UIViewController. thanks so much.

2条回答
smile是对你的礼貌
2楼-- · 2019-02-19 07:08

So, You have not implemented the

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

and

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell  

methods in your second implementation. Also, try putting an invisible button over the collection view cell and assign the tag to be the indexpath of that collectionview cell like this:

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell  
{
....
myButton.tag = indexpath.item
}

After this you may either implement a delegate callback from collectionviewcell class to the homepagetableviewcontroller class or push the detail view controller directly by code.

As far as setting of image in the detail view controller is concerned. You can do it both in viewdidLoad() or viewDidAppear(). Its fine.

查看更多
地球回转人心会变
3楼-- · 2019-02-19 07:15

The way you are going is correct, but you are creating one mistake.Try to implement UICollectionViewDelegate method didSelectItemAtIndexPath also inside TableViewCell and remove it from the HomePageTableViewController.

Now declare one protocol, after that create its instance inside TableViewCell and implement the protocol in the HomePageTableViewController, after that in the didSelectItemAtIndexPath use that delegate instance to call the method like this.

protocol PostDelegate {
    func selectedPost(post: Posts)
}

Now create its instance inside TableViewCell and call this delegate method in the didSelectItemAtIndexPath.

class TableViewCell: UITableViewCell, UICollectionViewDataSource, UICollectionViewDelegate {
     var posts1: [Posts] = [Posts]()
     var posts2: [Posts] = [Posts]()
     var categories: [Category] = [Category]()
     var selectedPost1: Posts?  
     var postDelegate: PostDelegate?

     func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
         postDelegate?. selectedPost(self.posts1[indexPath.row])
     }
}

Now implement this PostDelegate protocol inside HomePageTableViewController

class HomePageTableViewController: UITableViewController,UICollectionViewDelegate { 


     //Your code 

     func selectedPost(post: Posts) {
         //You will get your post object here, do what you want now
     }
}

Note: Inside cellForRowAtIndexPath don't forgot to set the delegate of postDelgate with your HomePageTableViewController like this

tableViewCell.postDelegate = self

Edit:

func selectedPost(post: Posts) {
    //You will get your post object here, do what you want now
    self.performSegueWithIdentifier("goToDetail", sender: post)
}

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    let post = sender as! Posts
    let postDetailPage = segue.destinationViewController as? DetailViewController
    postDetailPage.passPost = post
}
查看更多
登录 后发表回答