0

Hey i'm new to programming and my problem is, i have a UICollectionViewController with 4 cells that are horizontal scrollable. Inside of the 4th cell i have a UIButton(optionsButton) on top of a UIView (ProfileContainerView).

The UIViewController I want to present is called ProfileEditViewController and is set up in Main.storyboard.

How can i present a UIViewController after pressing this button?

ProfileCell:

class ProfileCell: UICollectionViewCell {

    let profileContainerView: UIView = {
        let view = UIView()
        return view
    }()

    lazy var optionsButton: UIButton = {
        let btn = UIButton(type: .custom)
        btn.setImage(#imageLiteral(resourceName: "Settings"), for: UIControlState.normal)
        btn.addTarget(self, action: #selector(handleOptionsButton), for: UIControlEvents.touchUpInside)
        return btn
    }()

    @objc func handleOptionsButton() {
        print("Button pressed")
    }
}

HomeViewController:

class HomeViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {


    let profileCelId = "profileCell"

    override func viewDidLoad() {
        super.viewDidLoad()
        setupSwipeView()
    }


    func setupSwipeView() {
        collectionView?.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cell)
        collectionView?.register(ProfileCell.self, forCellWithReuseIdentifier: profileCelId)        
    }


    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {        
        if indexPath.item == 3 {
            return collectionView.dequeueReusableCell(withReuseIdentifier: profileCelId, for: indexPath)
        }
        return cell
    }
}
Lepidopteron
  • 6,056
  • 5
  • 41
  • 53
Sam
  • 79
  • 1
  • 7
  • Check this : https://stackoverflow.com/questions/43766963/swift-action-button-inside-a-collectionviewcell – Amit Oct 19 '17 at 11:17

3 Answers3

1

You can use delegates to implement this.

Below is the code to implement this

 protocol ProfileCollectionViewCellDelegate {
 func buttonPressedAtIndexPath(inCell: ProfileCell)
 }

class ProfileCell: UICollectionViewCell {

var delegate : ProfileCollectionViewCellDelegate?
let profileContainerView: UIView = {
    let view = UIView()
    return view
}()

lazy var optionsButton: UIButton = {
    let btn = UIButton(type: .custom)
    btn.setImage(#imageLiteral(resourceName: "Settings"), for: UIControlState.normal)
    btn.addTarget(self, action: #selector(handleOptionsButton), for: UIControlEvents.touchUpInside)
    return btn
}()

@objc func handleOptionsButton() {
    if self.delegate != nil {
        self.delegate?.buttonPressedAtIndexPath(self)
    }
}
}

For your HomeViewController

 class HomeViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout, ProfileCollectionViewCellDelegate  {


let profileCelId = "profileCell"

override func viewDidLoad() {
    super.viewDidLoad()
    setupSwipeView()
}


func setupSwipeView() {
    collectionView?.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cell)
    collectionView?.register(ProfileCell.self, forCellWithReuseIdentifier: profileCelId)        
}


  override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {        

     let cell = collectionView.dequeueReusableCell(withReuseIdentifier: profileCelId, for: indexPath)
    cell.delegate = self
    return cell
 }

fun buttonPressedAtIndexPath(inCell: ProfileCell) {
       let indexOfCell = self.collectionView.indexPath(for: cell)
        if indexOfCell.row == 3 {
            //Do your work here
        }

}

}
Shuja Ud Din
  • 434
  • 5
  • 17
0

You can present your ProfileEditViewController, which is styled in your Main.storyboard the following way:

1) Give your ProfileEditViewController a StoryBoard ID. E.g. "ProfileEditViewController" - Some question regarding this is here: What is a StoryBoard ID and how can i use this?

2) Register the UIViewController for the action on the UIButton or offer an appropriate callback functionality. As your HomeViewController is also your Collection View's datasource, you can easily extend your DataSource method

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

Implementation could look like:

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {        
    if indexPath.item == 3 {
        let profileCell = collectionView.dequeueReusableCell(withReuseIdentifier: profileCelId, for: indexPath)
        if let _cell = cell as? ProfileCell,
           let button = _cell.optionsButton as? UIButton {
            button.addTarget(self, action: #selector(handleOptionsButton), forControlEvents: UIControlEvents.TouchUpInside)
        }
        return profileCell;
    }
    return cell
}

Make sure that your buttons Action is now also being implemented by your HomeViewController

@objc func handleOptionsButton() {
    print("Button pressed")
}

3) Now in HomeViewController.handleOptionsButton you need to provide a functionality to support the transition to that specific Controller with the desired StoryboardID:

let storyboard = UIStoryboard(name: "Main", bundle:Bundle.main)
let controller = storyboard.instantiateViewController(withIdentifier: "ProfileEditViewController")
self.present(controller, animated: true, completion: nil)
Lepidopteron
  • 6,056
  • 5
  • 41
  • 53
  • I tried but it shows that Value of type 'ProfileCell' has no member 'present' – Sam Oct 19 '17 at 11:35
  • present is a function implemented by `UIViewControllers` see here: https://developer.apple.com/documentation/uikit/uiviewcontroller/1621380-present. You can register your UIViewController for the action of the Uibutton for example. I will adjust my answer. – Lepidopteron Oct 19 '17 at 11:38
  • 1
    Ok I'll try this and let you know if it worked. Thanks for your time – Sam Oct 19 '17 at 12:07
  • after if let button = profileCell.optionsButton as? UIButton { button.addTarget(self, action: #selector(handleOptionsButton), forControlEvents: UIControlEvents.TouchUpInside) } – Sam Oct 19 '17 at 13:14
  • it says Value of type 'UICollectionViewCell' has no member 'optionsButton' – Sam Oct 19 '17 at 13:14
  • is there something wrong with the setup? func setupOptionsButton() { profileContainerView.addSubview(optionsButton) } – Sam Oct 19 '17 at 13:15
  • Well, the compiler was not aware of the cell being of type "ProfileCell" - I have updated the method – Lepidopteron Oct 19 '17 at 13:17
  • So i tried that and when i click the button, it only shows the print statement inside of ProfileCell and not the one in the HomeViewController. I commented ProfileCell.handleOptionsButton out and nothing is printed into the console. – Sam Oct 20 '17 at 08:21
  • As you Button appears to be declared as lazy, do you even get to the part where your button gets the target added: button.addTarget(self, action: #selector(handleOptionsButton), forControlEvents: UIControlEvents.TouchUpInside) - Set a breakpoint and investigate the issue. – Lepidopteron Oct 20 '17 at 08:35
  • 1
    Oh yes i got it and i learned a lot thanks. I added a comment if you wanna see what i did. – Sam Oct 20 '17 at 11:38
0

let proCell = ProfileCell()

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: self.cell, for: indexPath)
    if indexPath.item == 3 {
        let profileCell = collectionView.dequeueReusableCell(withReuseIdentifier: profileCelId, for: indexPath)
        let button = proCell.optionsButton
            button.addTarget(self, action: #selector(handleOptionsButton), for: UIControlEvents.touchUpInside)
        return profileCell;
    }
    return cell
}
Sam
  • 79
  • 1
  • 7