从 CollectionView Cell 以编程方式执行 Segue

Posted

技术标签:

【中文标题】从 CollectionView Cell 以编程方式执行 Segue【英文标题】:Performing Segue Programmatically from CollectionView Cell 【发布时间】:2017-07-21 01:15:04 【问题描述】:

我目前在集合视图单元格中创建了集合视图。 集合视图中的集合视图。我在第二个视图控制器中的didSelectItemAt 上执行转场或呈现视图控制器时遇到问题。现在,我尝试的所有操作都会导致崩溃,或者出现“视图不在视图层次结构中”错误。

来一张图说明:

这是我的代码:

集合视图 1:

class ExploreVC: UIViewController, UICollectionViewDataSource,UICollectionViewDelegate, UICollectionViewDelegateFlowLayout 


var businessView: UIViewController!

let foodCategory = exploreCategory()
let shopCategory = exploreCategory()
let cultureCategory = exploreCategory()
let nightlifeCategory = exploreCategory()

@IBOutlet weak var collectionView: UICollectionView!



override func viewWillAppear(_ animated: Bool) 
    collectionView.delegate = self
    collectionView.dataSource = self
    collectionView.backgroundColor = UIColor.clear
    collectionView.register(categoryCell.self, forCellWithReuseIdentifier: "category")

    exploreCategories = exploreCategory.setCategories()
    businessView = storyboard?.instantiateViewController(withIdentifier: "businessPage")






 func setCategories() -> [exploreCategory]


    foodCategory.name = "Good Food"


    shopCategory.name = "Shopping Near You"


    cultureCategory.name = "Cultural Highlights"


    nightlifeCategory.name = "Start Your Night"



    return [foodCategory,shopCategory,cultureCategory,nightlifeCategory]


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

    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "category", for: indexPath) as! categoryCell
    cell.exploreCategory = exploreCategories?[indexPath.item]
    return cell


func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 
    if let count =  exploreCategories?.count 

        return count
    

    return 0 


func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize 
    let size = CGSize(width: view.frame.width, height: 280)

    return size


func gotToBusinessPage() 


    print("gotToBusinessPage is being executed")
    let top: UIViewController? = 
UIApplication.shared.keyWindow?.rootViewController
    let businessPage = BusinessVC()
    top?.performSegue(withIdentifier: "toBusiness", sender: self)
    //top?.present(businessPage, animated: true)  _ in 

    //present(businessPage, animated: true)


集合视图 1 单元格:

import UIKit
import Foundation
import AlgoliaSearch
import SwiftyJSON
import AFNetworking

class categoryCell: UICollectionViewCell, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout 

private let cellId = "exploreCell"

//* MARK Algolia
var exploreSearch = [exploreBusiness]()
var businessIndex: AlgoliaSearch.Index!
let query = Query()
var searchId = 0
var displayedSearchId = -1
var loadedPage: UInt = 0
var nbPages: UInt = 0


//*MARK Set Cell Values
var exploreCategory: exploreCategory? 

    didSet 

        if let name = exploreCategory?.name 

            categoryLabel.text = name.uppercased()


        

    




//*MARK Init
override init(frame: CGRect) 
    super.init(frame: frame)
    setUpViews()
    searchFood(category: (exploreCategories?[0])!)
    searchShop(category: (exploreCategories?[1])!)
    searchCulture(category: (exploreCategories?[2])!)
    searchNightlife(category: (exploreCategories?[3])!)



required init?(coder aDecoder: NSCoder) 
    super.init(coder: aDecoder)



//*MARK UI Mark Up
let categoryLabel: UILabel = 

    let black = UIColor(red:0.29, green:0.29, blue:0.29, alpha:1.0)
    let label = UILabel()
    label.font = UIFont(name: "AvenirNext-DemiBold", size: 14)
    label.textColor = black
    label.text = "TRENDING NEAR YOU"
    label.translatesAutoresizingMaskIntoConstraints = false
    label.numberOfLines = 1

    return label

()

let businessCollectionView: UICollectionView = 

    let layout = UICollectionViewFlowLayout()
    layout.scrollDirection = .horizontal

    let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
    collectionView.translatesAutoresizingMaskIntoConstraints = false
    collectionView.backgroundColor = UIColor.clear
    return collectionView

()



//* MARK UI Set Up
func setUpViews()


    addSubview(businessCollectionView)
    addSubview(categoryLabel)

    businessCollectionView.dataSource = self
    businessCollectionView.delegate = self
    businessCollectionView.showsHorizontalScrollIndicator = false


    businessCollectionView.register(exploreCell.self, forCellWithReuseIdentifier: cellId)


    addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-16-[v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": categoryLabel]))

    addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": businessCollectionView]))

    addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[categoryLabel(24)][v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": businessCollectionView, "categoryLabel": categoryLabel]))





//*MARK CollectionView Set Up

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 
    if let count = exploreCategory?.businesses?.count 

        return count

    

    return 0


func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! exploreCell
    cell.business = exploreCategory?.businesses?[indexPath.item]


    return cell


func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize 
    let size = CGSize(width: 124, height: frame.height - 30)

    return size


func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets 
    return UIEdgeInsetsMake(0, 16, 0, 16)


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

    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! exploreCell
    cell.business = exploreCategory?.businesses?[indexPath.item]


    let cellData = cell.business
    businessName = (cellData?.businessName!)!
    businessID = (cellData?.objectID!)!
    businessType = (cellData?.businessType!)!
    zipcode = (cellData?.zipcode!)!
    state = (cellData?.state!)!
    address = (cellData?.address!)!
    city = (cellData?.city!)!
    hours = "\(cellData?.openTime! ?? "error") - \(cellData?.closeTime! ?? "error")"
    if cellData?.image1URL?.isEmpty == false 

        image1 = (cellData?.image1URL!)!
        images.append(image1)

    

    if cellData?.image2URL?.isEmpty == false 

        image2 = (cellData?.image2URL!)!
        images.append(image2)
    

    if cellData?.image3URL?.isEmpty == false 

        image3 = (cellData?.image3URL!)!
        images.append(image3)
    

    if cellData?.image4URL?.isEmpty == false 

        image4 = (cellData?.image4URL!)!
        images.append(image4)
    

    if cellData?.image5URL?.isEmpty == false 

        image5 = (cellData?.image5URL!)!
        images.append(image5)
    

    if cellData?.image6URL?.isEmpty == false 

        image6 = (cellData?.image6URL!)!
        images.append(image6)
    

    if cellData?.image7URL?.isEmpty == false 

        image7 = (cellData?.image7URL!)!
        images.append(image7)
    



    let tab = ExploreVC()

    tab.gotToBusinessPage()



    

第二个集合视图单元格:

import UIKit
import AlamofireImage
import Alamofire

class exploreCell: UICollectionViewCell 

weak var exploreVC : ExploreVC?
var mainVC = ExploreVC()

var business: exploreBusiness? 

    didSet 


        nameLabel.text = business?.businessName
        reviewLabel.text = "\(business?.reviewCount! ?? 0) Reviews"

        let url = URL(string: (business?.image1URL)!)
        Alamofire.request(url!).responseImage  response in


            if let image = response.result.value 

                self.imageView.image = image


            
        


     





override init(frame: CGRect) 
    super.init(frame: frame)
    setUpViews()


required init?(coder aDecoder: NSCoder) 
    super.init(coder: aDecoder)


let imageView: UIImageView = 
let iv = UIImageView()

    iv.contentMode = .scaleAspectFill
    iv.layer.cornerRadius = 4
    iv.layer.masksToBounds = true
    return iv

()

let nameLabel: UILabel = 

    let black = UIColor(red:0.29, green:0.29, blue:0.29, alpha:1.0)
    let label = UILabel()
    label.text = "Paradise Diner"
    label.font = UIFont(name: "AvenirNext-DemiBold", size: 14)
    label.textColor = black
    label.numberOfLines = 2
    return label

()

let reviewIcon: UIImageView = 
    let iv = UIImageView()
    iv.image = #imageLiteral(resourceName: "review-black")
    iv.contentMode = .scaleAspectFill
    iv.layer.masksToBounds = true
    return iv

()

let reviewLabel: UILabel = 

    let black = UIColor(red:0.29, green:0.29, blue:0.29, alpha:1.0)
    let label = UILabel()
    label.text = "45 Reviews"
    label.font = UIFont(name: "AvenirNext-DemiBold", size: 14)
    label.textColor = black
    label.numberOfLines = 1
    return label

()


func setUpViews()

    addSubview(imageView)
    addSubview(nameLabel)
    addSubview(reviewIcon)
    addSubview(reviewLabel)

    let ImageRect = CGRect(x: 0, y: 0, width: frame.width, height: 182)
    let nameLabelRect = CGRect(x: 0, y: 190 , width: frame.width, height: 20)
    let reviewRect = CGRect(x: 0, y: 220 , width: 16, height: 11)
    let reviewLabelRect = CGRect(x: 22, y: 217 , width: frame.width - 16, height: 16)



    imageView.frame = ImageRect
    nameLabel.frame = nameLabelRect
    reviewIcon.frame = reviewRect
    reviewLabel.frame = reviewLabelRect

    


如果不清楚,我很乐意解释更多。

【问题讨论】:

CollectionView 委托方法应该在控制器 ExploreVC 中,而不是在单元格中。 单元格中有一个委托方法,因为它是集合视图中的集合视图 【参考方案1】:

你的代码的问题是这一行:

let tab = ExploreVC()

这不是要求您当前的 ExploreVC 执行此操作,而是要求新创建的实例执行此操作(这就是它失败的原因)。

你必须做的来解决这个问题(不要过多地修改你的代码)是:

1) 在“categoryCell”中添加一个弱变量来引用实际的 ExploreVC:

weak var exploreVC : ExploreVC?

2) 在 ExploreVC 的“cellForItemAt”中添加对它的引用:

let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "category", for: indexPath) as! categoryCell
cell.exploreCategory = exploreCategories?[indexPath.item]
cell.exploreVC = self
return cell

3) 在 didSelectItem 函数中删除“let tab = ExploreVC()”并添加它:

exploreVC?.gotToBusinessPage()

【讨论】:

我正在尝试从第二个集合视图的单元格中执行或呈现视图控制器。 (黑色细胞) 然后将引用传递给那个。关键是您必须让您的 ExploreVC 执行 segue,而不是像您似乎正在做的新实例。 但是如果它在 categoryCell 类中,我如何将它设置为 self?或者我可以在里面设置为 self 吗? 我想通了!我将weak var设为全局变量,并在ExploreVC的viewDidLoad中设置为self

以上是关于从 CollectionView Cell 以编程方式执行 Segue的主要内容,如果未能解决你的问题,请参考以下文章

点击 CollectionView Cell 按钮以播放来自特定阵列的声音并从特定阵列复制电影

点击CollectionView Cell的下半部分时推动ViewController

Imageview 未显示在以编程方式创建的 collectionview 中

collectionView 中cell间距设置建议

将现有视图添加到 collectionview-cell

以编程方式从 collectionView 内的自定义 tableView 中进行 Segue