【问题标题】:How to push a UIViewController programmatically from "didSelectItemAt" in UICollectionView (using separate files)?如何从 UICollectionView 中的“didSelectItemAt”以编程方式推送 UIViewController(使用单独的文件)?
【发布时间】:2020-02-03 08:58:44
【问题描述】:

我在 HomeViewController 上显示的单独 swift 文件中设置了 UICollectionView。我想在选择集合视图单元格时推送一个 DetailViewController。我想以编程方式做到这一点,没有故事板。我一直使用“navigationController.pushViewController(vc, animated: true)”推送 ViewController,但我无法从 UICollectionView 的“didSelectItemAt”函数中访问 navigationController。如果重要的话,我确实设置了一个自定义 UICollectionViewCell 并用于单元格。

我怎样才能做到这一点? collectionView 显示正确,当我选择一个单元格时,我知道 didSelectItemAt 正在运行,因为我的打印语句“Did select item at ...”显示在控制台中。

经过数小时的谷歌搜索,我无法弄清楚。我仍在学习 M-V-C 结构,所以我可能在一切设置方面存在根本缺陷。我还看到我可能需要创建一个自定义委托来处理这个问题,但我觉得我缺少一些更简单的东西,因为 didSelectItemAt 函数就在那里。

这是我的 UICollectionView swift 文件中的相关代码:

class HomeDataController: NSObject, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

        print("Did select item at...")
        // this is where I am trying to push the DetailViewController

    }
}

这是我的 HomeViewController:

class HomeViewController: UIViewController {

    let collectionView: UICollectionView = {
            let layout = UICollectionViewFlowLayout()
            layout.scrollDirection = .vertical
            layout.minimumLineSpacing = 30
            layout.sectionInset.top = 20
            layout.sectionInset.bottom = 20

            let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
            cv.translatesAutoresizingMaskIntoConstraints = false
            cv.backgroundColor = UIColor(named: "background")
            cv.register(HomeCustomCell.self, forCellWithReuseIdentifier: "homeCell")
            return cv
        }()

    let dataController: HomeDataController = {
        let dataController = HomeDataController()
        return dataController
    }()


    override func viewDidLoad() {
        super.viewDidLoad()

        collectionView.dataSource = self.dataController
        collectionView.delegate = self.dataController

        view.addSubview(collectionView)
    }
}

【问题讨论】:

  • 您需要将对 navigationController 的引用传递到您打算从中推送的对象中。
  • 谢谢!我不知道如何完成你所说的,所以我最终尝试了另一个评论者答案中的代表。

标签: ios swift view uiviewcontroller uicollectionview


【解决方案1】:
class HomeViewController: UIViewController {

let collectionView: UICollectionView = {
            let layout = UICollectionViewFlowLayout()
            layout.scrollDirection = .vertical
            layout.minimumLineSpacing = 30
            layout.sectionInset.top = 20
            layout.sectionInset.bottom = 20

            let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
            cv.translatesAutoresizingMaskIntoConstraints = false
            cv.backgroundColor = UIColor(named: "background")
            cv.register(HomeCustomCell.self, forCellWithReuseIdentifier: "homeCell")
            return cv
        }()

    lazy var dataController: HomeDataController = {
        let dataController = HomeDataController(controller: self)
        dataController.didSelectionCompletion = { indexPath in
            print("Called...")
        }
        dataController.delegate = self
        return dataController
    }()


    override func viewDidLoad() {
        super.viewDidLoad()

        collectionView.dataSource = self.dataController
        collectionView.delegate = self.dataController

        view.addSubview(collectionView)
    }
}

//MARK: - HomeDataControllerDelegate 
extension HomeViewController : HomeDataControllerDelegate {
    func homeDataController(_ controller: HomeDataController, didSelectItemAt: IndexPath) {
        print("Called..")
    }
}

HomeDataController.swift

protocol HomeDataControllerDelegate {
    func homeDataController(_ controller : HomeDataController, didSelectItemAt : IndexPath)
}


class HomeDataController: NSObject, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {

    private var controller : UIViewController? = nil

    var delegate : HomeDataControllerDelegate? = nil

    var didSelectionCompletion : ((IndexPath) -> (Void))? = nil

    override init() {
        super.init()
    }

    init(controller : UIViewController) {
        super.init()
        self.controller = controller
    }


    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

        print("Did select item at...")
        // this is where I am trying to push the DetailViewController

        /* Method1 - using property*/
        let detialController = UIViewController()
        controller?.navigationController?.pushViewController(detialController, animated: true)

        /* Method2 - delegate */
        delegate?.homeDataController(self, didSelectItemAt: indexPath)

        /* Method3 - Block */
        self.didSelectionCompletion?(indexPath)
    }
}

使用方法 1(使用属性)存在 HomeDataController 总是只推送一个细节控制器的限制。它已成为依赖类。还有选项将目标控制器传递给HomeDataControllerinit 方法,它再次变得更加复杂。但是如果你有修复 detailViewController 那么你可以使用这个方法。但它不是任何特定更改请求的可扩展代码。

块和委托是更标准和可扩展的选项。使用这种方法,我们可以完全控制 UIController 和任何操作。

希望对你有帮助。

【讨论】:

  • 使用委托(方法2)效果很好!谢谢!还要感谢您提供有关块、委托和属性的其他有用信息。我将深入研究这些以加深我的理解。再次感谢!!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-26
  • 1970-01-01
  • 2018-09-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多