PrepareForSegue from a UIButton in a custom prototype cell

痴心易碎 提交于 2019-12-07 11:54:07

问题


As the title say I have a tableView with prototype cell; cell is a custom cell (so I made a class called CustomCell.swift in witch I created the IBOutlet for image, label, button etc); here my class

import UIKit

class CustomCell: UITableViewCell
{
    @IBOutlet var imageSquadra: UIImageView!
    @IBOutlet var button: UIButton!

    override func awakeFromNib()
    {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(selected: Bool, animated: Bool)
    {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }
}

then I made the UITableViewController:

import UIKit

class SquadreController: UITableViewController
{
    var index: NSIndexPath?
    var isScrolling = Bool()

    override func viewDidLoad()
    {
        super.viewDidLoad()

        DataManager.sharedInstance.createCori()

    }

    override func didReceiveMemoryWarning()
    {
        super.didReceiveMemoryWarning()
    }

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int
    {
        return 1
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
    {
        return DataManager.sharedInstance.arrayCori.count
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
    {
        let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! CustomCell
        let squadra = DataManager.sharedInstance.arrayCori[indexPath.row]

        cell.backgroundColor = UIColor.clearColor()

        if (indexPath.row % 2 == 0)
        {
            cell.backgroundColor = UIColor.greenColor()
        }
        else
        {
            cell.backgroundColor = UIColor.blueColor()
        }

        //Here I added target to the button in the cell, and below in the class I implemented the fun makeSegue()
        cell.button.addTarget(self, action: "makeSegue", forControlEvents: UIControlEvents.TouchUpInside)

        return cell
    }


    //Following 4 method are used to detect UIScollView scrolling and to change cell height.
    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
    {
        tableView.deselectRowAtIndexPath(indexPath, animated: true)
        index = indexPath
        tableView.beginUpdates()
        tableView.endUpdates()
    }

    override func scrollViewWillBeginDragging(scrollView: UIScrollView)
    {
        isScrolling = true
        tableView.beginUpdates()
        tableView.endUpdates()
    }

    override func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool)
    {
        isScrolling = false
    }

    override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
    {
        if isScrolling
        {
            return 100
        }

        if index == indexPath
        {
            return 200
        }
        else
        {
            return 100
        }
    }

    //Here I implemented the makeSegue() func, the action I had made as target of the button.
    func makeSegue() {
        self.performSegueWithIdentifier("toCoriViewController", sender: self)
    }
}

Ok ok now comes the hard part: to make the prepareForSegue; I do not have any ideas how to solve this problem, I tried

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
    {
        if segue.identifier == "toCoriViewController"
        {
            if let indexPath = ?????????????
            {
                let controller = segue.destinationViewController as! CoriViewController
                controller.coriSquadra = DataManager.sharedInstance.arrayCori[indexPath.row]
            }
        }
    }

but I don't know how to set the constant indexPath.

Oh, first of all I made a segue by control-right from the button to the second controller: maybe I must make that segue from the tableView cell???

Hope someone could help me!


回答1:


You could get the index path of the cell like so

let indexPath : NSIndexPath
if let button = sender as? UIButton {
    let cell = button.superview?.superview as! UITableViewCell
    indexPath = self.tableView.indexPathForCell(cell)
}

You'll also need to change your makeSegue like this:

func makeSegue(button:UIButton) {
    self.performSegueWithIdentifier("toCoriViewController", sender: button)
}

and in your cellForRowAtIndexPath just change the line where you set the action to cell.button.addTarget(self, action: "makeSegue:", forControlEvents: UIControlEvents.TouchUpInside).

Alternatively, you could create a squadra property inside your custom cell class to hold the arrayCori value of that cell, so you'd have some code that looks like this:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
    let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! CustomCell
    let squadra = DataManager.sharedInstance.arrayCori[indexPath.row]
    cell.squadra = squadra #add this line
    cell.backgroundColor = UIColor.clearColor()
    if (indexPath.row % 2 == 0)
    {
        cell.backgroundColor = UIColor.greenColor()
    }
    else
    {
        cell.backgroundColor = UIColor.blueColor()
    }

    //Here I added target to the button in the cell, and below in the class I implemented the fun makeSegue()
    cell.button.addTarget(self, action: "makeSegue", forControlEvents: UIControlEvents.TouchUpInside)

    return cell
}

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
    if segue.identifier == "toCoriViewController"
    {
        let controller = segue.destinationViewController as! CoriViewController
        if let button = sender as? UIButton {
            let cell = button.superview?.superview as! CustomCell
            controller.coriSquadra = cell.squadra
        }
    }
}



回答2:


Storyboard + prepareForSegue

It can be done with just about no code by adding a separate UIStoryboardSegue with its own identifier for the button in the Storyboard.

prepareForSegue becomes:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if "fromButtonToViewController" == segue.identifier {
        if let button = sender as? UIButton {
            // ... The UIButton is the sender
        }
    }
}

This handles both tap on cell and tap on button either jointly or separately, passes the proper sender to prepare:segue:sender, thus allowing customization of the cell, the button, the transition, and ultimately the target view. The demonstration of this statement can be found in the compact project below.


► Find this solution on GitHub and additional details on Swift Recipes.




回答3:


For those who are looking for a generic approach.

/* Generic function to get uitableviewcell from any UIKit controllers which stored in deep level of views or stackviews */

func getCell<T>(_ view: T) -> UITableViewCell? {

    guard let view = view as? UIView else {
        return nil
    }

    return view as? UITableViewCell ?? getCell(view.superview)
}


override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
    if segue.identifier == "toCoriViewController"
    {
        if let button = sender as? UIButton,
            let cell = getCell(button),
            let indexPath = tableView.indexPath(for: cell)
        {
            let controller = segue.destinationViewController as! CoriViewController
            controller.coriSquadra = DataManager.sharedInstance.arrayCori[indexPath.row]
        }
    }
}


来源:https://stackoverflow.com/questions/32341629/prepareforsegue-from-a-uibutton-in-a-custom-prototype-cell

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!