Search code examples
iosswiftstoryboarduikitadyen

How to present Adyen checkout if i'm already presenting a controller?


i'm facing a problem, i'm using a tableview as sidebar to present certain controller from the app. When trying to preset Adyen checkout for payment getting an error that tells me i cannot use multi presenting, my question is, how can i fix this issue?

I was thinking to dismiss the sidebar after the button for checkout is pressed or to push the side bar and present the other controllers, but with no success or i didn't do it right.

Thank you!

This is the side menu button placed in MainViewController

public func setSideMenuButton()
    {
        let button = UIButton()
        button.frame = CGRect(x: self.view.frame.size.width - 65, y: self.view.frame.size.height - 160, width: 50, height: 50)
        button.setImage(#imageLiteral(resourceName: "side_menu_button").withRenderingMode(.alwaysOriginal), for: .normal)
        button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
        self.view.addSubview(button)

    }
    
    @objc func buttonAction(sender: UIButton!)
    {
        pauseEachExistingVideoPlayer()
        
        guard let sideMenuViewController = storyboard?.instantiateViewController(withIdentifier: "SideMenuViewController") as? SideMenuViewController else { return }
      
        sideMenuViewController.modalPresentationStyle = .overCurrentContext
        sideMenuViewController.transitioningDelegate = self
        present(sideMenuViewController, animated: true)
    } 

Presenting each index from the tabel

 override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
    {
    
        switch indexPath.row {
        case 0: present( UIStoryboard(name: "Profile", bundle: nil).instantiateViewController(withIdentifier: "UserProfileVC") as UIViewController, animated: true, completion: nil)
        case 1: present( UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "SR_VideoLibrary") as UIViewController, animated: true, completion: nil)
        case 2: present( UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "SR_Livestream") as UIViewController, animated: true, completion: nil)
        case 3: return
        case 4: return
        case 5: present( UIStoryboard(name: "VideoLibrary", bundle: nil).instantiateViewController(withIdentifier: "ProjectsListVC") as UIViewController, animated: true, completion: nil)
        case 6: present( UIStoryboard(name: "Profile", bundle: nil).instantiateViewController(withIdentifier: "GetPremiumVC") as UIViewController, animated: true, completion: nil)
            
        default:
            break
        } 
    }

This is how i dismiss the contrainer view and close the sidebar when tapped outside

class SideMenuViewController: UIViewController, UITableViewDelegate
{
    @IBOutlet weak var modalView: UIView!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        if let view = modalView
        {
            addTapGesture(target: view, action: #selector(dismissController))
        }
       
    }
    
    @objc private func dismissController()
    {
        dismiss(animated: true, completion: nil)
    }

}
extension SideMenuViewController {
    func addTapGesture(target: UIView, action: Selector, numberOfTaps: Int = 1) {
        let tap = UITapGestureRecognizer(target: self, action: action)
        tap.numberOfTapsRequired = numberOfTaps
        target.isUserInteractionEnabled = true
        target.addGestureRecognizer(tap)
    }
}

This is the side menu storyboard


Solution

  • I am afraid that's a limitation in UIKit, a View Controller can present only one other ViewController.

    So how I see it, you have two choices, either dismiss the already presented SideMenuViewController first, or make the SideMenuViewController present the Adyen view controller.

    If you are using Adyen checkout SDK 3.5.0, there is a helper property added to every instance of a UIViewController that gets the top most presented view controller, use this property of the MainViewController -or any other view controller that would make sense to present the adyen checkout view controller- to present another one on top of it.

    presenterViewController.adyen.topPresenter.present(secondPresentedVC, animated: true)
    

    if you're using a version of the SDK in which this adyen helper is not present, you can implement an extension of UIViewController as follows:

    extension UIViewController {
    
        var topPresenter: UIViewController {
            var topController: UIViewController = self
            while let presenter = topController.presentedViewController {
                topController = presenter
            }
            return topController
        }
    
    }
    

    Hope this helps!.