简体   繁体   English

集合视图单元格导航

[英]Collection view cell navigation

Dear fellow coders please help me. 亲爱的编码员,请帮助我。 I started to learn Swift 2 months ago and this will be my first app if I will be able to finish... First of all, I don't use storyboard. 我2个月前开始学习Swift,如果可以完成的话,这将是我的第一个应用程序。首先,我不使用情节提要。 In my app, there are collection views in main window. 在我的应用程序中,主窗口中有集合视图。 When you tap the image in the cells, for example the cat image in the cat cell, Cat.swift file should open. 当您点击单元格中的图像(例如,cat单元格中的cat图像)时,应打开Cat.swift文件。 But I can't implement it yet. 但是我还不能实现它。 And in the same way if you tap the dog image, Dog.swift file should be viewed. 并且,如果您点击狗图像,则应以相同的方式查看Dog.swift文件。 Here is the code. 这是代码。

this is the main screen when you open the app: 这是打开应用程序时的主屏幕:

import UIKit

class FeaturedAnimalsController: UICollectionViewController, UICollectionViewDelegateFlowLayout {

    var animalCategories: [AnimalCategory]?

    private let cellId = "cellId"

    override func viewDidLoad() {
        super.viewDidLoad()

        animalCategories = AnimalCategory.sampleAnimalCategories()

        collectionView?.backgroundColor = .white
        collectionView?.register(CategoryCell.self, forCellWithReuseIdentifier: cellId)
    }

    func showAnimalDetailForAnimal(animal: Animal) {
        let layout = UICollectionViewFlowLayout()
        let animalDetailController = AnimalDetailController(collectionViewLayout: layout)
        animalDetailController.animal = animal
        navigationController?.pushViewController(animalDetailController, animated: true)
    }


    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        if let count = animalCategories?.count {
            return count
        }
        return 0
    }

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

        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! CategoryCell

        cell.featuredAnimalsController = self

        cell.animalCategory = animalCategories?[indexPath.item]

        return cell
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: view.frame.width, height: 230)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    } 
}

This is the CategoryCell: 这是CategoryCell:

import UIKit

class CategoryCell: UICollectionViewCell, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {

    var featuredAnimalsController: FeaturedAnimalsController?

    var animalCategory: AnimalCategory? {
        didSet {
            if let name = animalCategory?.name {
                nameLabel.text = name
            }
        }
    }

    private let cellId = "animalCellId"

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        if let count = animalCategory?.animals?.count {
            return count
        }
        return 0
    }


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

        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! AnimalCell
        cell.animal = animalCategory?.animals?[indexPath.item]
        return cell
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: 100, height: frame.height - 32)
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        return UIEdgeInsets(top: 0, left: 14, bottom: 0, right: 14)
    }

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        if let animal = animalCategory?.animals![indexPath.item] {
            featuredAnimalsController?.showAnimalDetailForAnimal(animal: animal)
        }
    }

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

        setupViews()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    let nameLabel: UILabel = {
        let label = UILabel()
        label.text = "Cardiology"
        label.font = UIFont.systemFont(ofSize: 16)
        //label.numberOfLines = 1  --> DEFAULT
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()

    let animalsCollectionView: UICollectionView = {
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .horizontal
        let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
        collectionView.backgroundColor = .clear
        collectionView.translatesAutoresizingMaskIntoConstraints = false
        return collectionView
    }()

    func setupViews() {
        backgroundColor = .clear

        animalsCollectionView.dataSource = self
        animalsCollectionView.delegate = self

        animalsCollectionView.register(AnimalCell.self, forCellWithReuseIdentifier: cellId)


        addSubview(nameLabel)
        addSubview(animalsCollectionView)

        addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-14-[v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": nameLabel]))
        addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": animalsCollectionView]))
        addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[nameLabel(30)][v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": animalsCollectionView, "nameLabel": nameLabel]))

    }


}

class AnimalCell: UICollectionViewCell {

    var animal: Animal? {
        didSet {
            if let name = animal?.name {
                nameLabel.text = name
            }
            categoryLabel.text = animal?.category

            if let imageName = animal?.imageName {
                imageView.image = UIImage(named: imageName)
            }
        }
    }

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

        setupViews()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func setupViews() {
        backgroundColor = .clear

        addSubview(categoryLabel)
        addSubview(imageView)
        addSubview(nameLabel)

        categoryLabel.frame = CGRect(x: 0, y: frame.width + 38, width: frame.width, height: 20)
        imageView.frame = CGRect(x: 0, y: 0, width: frame.width, height: frame.width)
        nameLabel.frame = CGRect(x: 0, y: frame.width + 2, width: frame.width, height: 40)

    }

    let imageView: UIImageView = {
        let iv = UIImageView()
        //iv.image = UIImage(named: "cat")
        iv.contentMode = .scaleAspectFill
        iv.translatesAutoresizingMaskIntoConstraints = false
        iv.layer.cornerRadius = 16
        iv.layer.masksToBounds = true
        return iv
    }()

    let nameLabel: UILabel = {
        let label = UILabel()
        label.text = ""
        label.font = UIFont.systemFont(ofSize: 14)
        label.numberOfLines = 2
        return label
    }()

    let categoryLabel: UILabel = {
        let label = UILabel()
        label.text = ""
        label.font = UIFont.systemFont(ofSize: 13)
        label.numberOfLines = 2
        return label
    }()  
}

This is the animal category model: 这是动物类别模型:

import UIKit

class AnimalCategory: NSObject {

    var name: String?
    var animals: [Animal]?

    static func sampleAnimalCategories() -> [AnimalCategory] {


        let catFamilyCategory = AnimalCategory()
        catFamilyCategory.name = "Cat Family"
        var catFamilyAnimals = [Animal]()

        let catAnimal = Animal()
        catAnimal.name = "Cat"
        catAnimal.imageName = "cat"
        catAnimal.category = "Lovely"
        //catAnimal.dvcName = Cat.self()
        catFamilyAnimals.append(catAnimal)

        catFamilyCategory.animals = catFamilyAnimals



        let dogFamilyCategory = AnimalCategory()
        dogFamilyCategory.name = "Dog Family"
        var dogFamilyAnimals = [Animal]()

        let dogAnimal = Animal()
        dogAnimal.name = "Dog"
        dogAnimal.imageName = "dog"
        dogAnimal.category = "Friendly"
        //dogAnimal.dvcName = Dog.self
        dogFamilyAnimals.append(dogAnimal)

        dogFamilyCategory.animals = dogFamilyAnimals


        return [catFamilyCategory, dogFamilyCategory]
    }
}

This is the animal model: 这是动物模型:

import UIKit

class Animal: NSObject {

    //var id: NSNumber?
    var name: String?
    var category: String?
    var imageName: String?
    //var dvc: AnimalDetailController?

}

This is the animal detail controller and sample cat.swift: 这是动物详细信息控制器和样本cat.swift:

import UIKit

class AnimalDetailController: UICollectionViewController, UICollectionViewDelegateFlowLayout {

    var animal: Animal? {
        didSet {
            navigationItem.title = animal?.name
        }
    }
}

class Cat: AnimalDetailController {
    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .brown
    }
}

After some changes thanks to @Paulw11, here is the code to present specific detail view controller for each animal: 经过@ Paulw11的一些更改后,下面的代码为每个动物展示了特定的细节视图控制器:

func showAnimalDetailFor(_ animal: Animal) {
        let layout = UICollectionViewFlowLayout()

        var dvc = animal.dvc
        dvc = AnimalDetailController(collectionViewLayout: layout)
        self.show(dvc, sender: self)
    }

Here is the animal and animal category model: 这是动物和动物类别模型:

struct Animal {

    let name: String
    let category: String
    let imageName: String
    let dvc: AnimalDetailController

}

struct AnimalCategory {

    var name: String
    private var _animals = [Animal]()

    var animals: [Animal] {
        get {
            return self._animals
        }
    }

    init(name: String) {
        self.name = name
    }

    static var sampleAnimalCategories: [AnimalCategory] = {

        var dogFamily = AnimalCategory(name: "Dog Family")
        dogFamily.addAnimal(Animal(name: "Dog", category: "Friendly", imageName: "dog", dvc: DogDetailViewController()))

        var catFamily = AnimalCategory(name: "Cat Family")
        catFamily.addAnimal(Animal(name: "Cat", category: "Lovely", imageName: "cat", dvc: CatDetailViewController()))

        let categories = [dogFamily,catFamily]
        return categories
    }()

    mutating func addAnimal(_ animal: Animal) {
        self._animals.append(animal)
    }

}

And animal detail controller class: 和动物细节控制器类:

class AnimalDetailController: UICollectionViewController, UICollectionViewDelegateFlowLayout {


    var animal: Animal? {
        didSet {
            navigationItem.title = animal?.name
        }
    }
}

I don't wont transfer data between view controllers. 我不会在视图控制器之间传输数据。 I am planning to make specific swift files for each animal in the cell and then when you tp their icon I want those swift file to show up. 我计划为单元中的每只动物制作特定的快速文件,然后当您点按它们的图标时,我希望这些快速文件显示出来。 And of course I am using nav controller and set it in app delegate. 当然,我正在使用导航控制器,并在应用程序委托中进行设置。

Please help me. 请帮我。 Thank you all. 谢谢你们。

In general, I would caution against tightly coupling your data and your code, but you can do what you want by storing a reference to the view controller class in your data model; 通常,我会警告不要将数据和代码紧密耦合,但是您可以通过在数据模型中存储对视图控制器类的引用来完成所需的操作; You almost had it correct in your commented code; 您在注释的代码中几乎正确无误。 you just don't need the () after self . 您只需要self之后不需要()

It is best practice to use structs if you don't need mutability, so your Animal and AnimalCategory objects could be structs. 如果您不需要可变性,则最佳做法是使用结构,因此您的AnimalAnimalCategory对象可以是结构。 You can also avoid all of those optionals. 您也可以避免所有这些可选选项。

struct Animal {
    let name: String
    let category: String
    let imageName: String
    let dvc: AnimalDetailController.Type
}

struct AnimalCategory {

    var name: String

    private var _animals = [Animal]()

    var animals: [Animal] {
        get {
            return self._animals
        }
    }

    init(name: String) {
        self.name = name
    }

    static var sampleAnimalCategories: [AnimalCategory] = {

        var dogs = AnimalCategory(name: "Dog Family")
        dogs.addAnimal(Animal(name: "Dog", category: "Friendly", imageName: "dog", dvc: DogDetailViewController.self))

        var cats = AnimalCategory(name: "Cat Family")
        cats.addAnimal(Animal(name: "Cat", category: "Lovely", imageName: "cat", dvc: CatDetailViewController.self))

        let categories = [dogs,cats]
        return categories
    }()

    mutating func addAnimal(_ animal: Animal) {
        self._animals.append(animal)
    }

}

Then your showAnimalDetailForAnimal will be something like: 然后,您的showAnimalDetailForAnimal将类似于:

func showAnimalDetailFor(_ animal: Animal) {
    let dvc = animal.dvc.init() 
    self.show(dvc, sender: self)
}

There is also a lot of cleaning up you can do with regard to your use of optionals. 关于使用可选组件,还可以进行很多清理工作。 For example, animals , and animalCategories could all be implicitly unwrapped optionals. 例如, animalsanimalCategories都可以是隐式解包的可选animalCategories

You won't be able to have your AnimalDetailViewController subclass UICollectionViewController since you can't initialise with a layout. 由于无法使用布局初始化,因此您将无法使用AnimalDetailViewController子类UICollectionViewController You will need to subclass UIViewController and add the collection view in your viewDidLoad 您将需要UIViewController并将其添加到viewDidLoad

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM