以编程方式将collectionView放在视图中

时间:2018-04-09 21:46:26

标签: swift view uicollectionview programmatically-created

我想以编程方式在navigationBar,标签和底部的tabBar之间放置一个collectionView。

我不希望不同部分之间有任何间距,如何正确地将视图添加到视图中?什么是最好的方法呢?

enter image description here

import UIKit

private let reUseIdentifierCollectionView = "CollectionViewCell1"

class CVControllerViewController: UIViewController {


    var heightNavigationBarTop: CGFloat{
        get{
            let barHeight = self.navigationController?.navigationBar.frame.height ?? 0
            let statusBarHeight = UIApplication.shared.isStatusBarHidden ? CGFloat(0) : UIApplication.shared.statusBarFrame.height
            return barHeight + statusBarHeight
        }
    }
    //Here I am getting the SafeArea above the NavigationBar
    var topSafeArea: CGFloat{
        get{
            var topSafeArea: CGFloat
            if #available(iOS 11.0, *) {
                topSafeArea = view.safeAreaInsets.top
            } else {
                topSafeArea = topLayoutGuide.length

            }
            return topSafeArea
        }
    }

    var tabBarHeight: CGFloat{ get{ return (self.tabBarController?.tabBar.frame.height)! } }

    lazy var label: UILabel = {
        let lb = UILabel()
        lb.frame = CGRect(x: 0, y: heightNavigationBarTop + topSafeArea, width: view.frame.width, height: 50)
        lb.backgroundColor = .red
        return lb
    }()

    var collectionView: UICollectionView!
    var content = [Int: Any]()

    override func viewDidLoad() {
        super.viewDidLoad()
        loadContent()
        loadCollectionView()
        view.addSubview(label)
        view.addSubview(collectionView)
    }


    func loadCollectionView() {
        let layout = UICollectionViewFlowLayout()
        let frame = CGRect(x: 0, y: heightNavigationBarTop + label.frame.height + topSafeArea, width: self.view.frame.height, height: self.view.frame.height - (heightNavigationBarTop + label.frame.height + tabBarHeight + topSafeArea))
        collectionView = UICollectionView(frame: frame, collectionViewLayout: layout)
        collectionView.backgroundColor = .white
        collectionView.register(CoinCVCCell.self, forCellWithReuseIdentifier: reUseIdentifierCollectionView)
        if let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
            flowLayout.scrollDirection = .horizontal
            flowLayout.minimumLineSpacing = 0
        }
        collectionView.delegate   = self
        collectionView.dataSource = self
    }

    func loadContent() {
        content[0] = Content(name: "Blau", color: .blue)
        content[1] = Content(name: "Grün", color: .green)
        content[2] = Content(name: "Gelb", color: .yellow)
        content[3] = Content(name: "brown", color: .brown)
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

}

extension CVControllerViewController: UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 4
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let outputCell: UICollectionViewCell
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reUseIdentifierCollectionView, for: indexPath) as! CoinCVCCell
        cell.content = (content[indexPath.item] as! Content)
        outputCell = cell
        return outputCell
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 0
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let width = view.frame.width
        let height = view.frame.height - (heightNavigationBarTop + label.frame.height + topSafeArea + tabBarHeight)

        let output = Utility.shared.CGSizeMake(width, height)
        return output
    }
}


class BaseCell: UICollectionViewCell {
    override init(frame: CGRect) {
        super .init(frame: frame)
        setUpViews()
    }
    func setUpViews() {

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

class CoinCVCCell: BaseCell {
    var content: Content? {
        didSet{
            backgroundColor = content?.color
        }
    }
}

class Content {
    var name: String?
    var color: UIColor?
    init(name: String, color: UIColor) {
        self.name = name
        self.color = color
    }
}

final class Utility: NSObject {
    private override init() { }
    static let shared = Utility()

    func CGRectMake(_ x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat) -> CGRect {
        return CGRect(x: x, y: y, width: width, height: height)
    }

    func CGSizeMake( _ width:CGFloat, _ height:CGFloat) -> CGSize{
        return CGSize(width: width, height: height)
    }
}

我不明白为什么collectionView不适合空间,以及边缘出现的原因,因为我从视图的总高度中减去视图上不同元素的高度。

编辑:

private let reUseIdentifierCollectionView = "CollectionViewCell1"

class CVControllerViewController: UIViewController {


    var heightNavigationBarTop: CGFloat{
        get{
            let barHeight = self.navigationController?.navigationBar.frame.height ?? 0
            let statusBarHeight = UIApplication.shared.isStatusBarHidden ? CGFloat(0) : UIApplication.shared.statusBarFrame.height
            return barHeight + statusBarHeight
        }
    }
    //Here I am getting the SafeArea above the NavigationBar
    var topSafeArea: CGFloat{
        get{
            var topSafeArea: CGFloat
            if #available(iOS 11.0, *) {
                topSafeArea = view.safeAreaInsets.top
            } else {
                topSafeArea = topLayoutGuide.length
            }
            return topSafeArea
        }
    }

    var tabBarHeight: CGFloat{ get{ return (self.tabBarController?.tabBar.frame.height)! } }

    lazy var label: UILabel = {
        let lb = UILabel()
        //lb.frame = CGRect(x: 0, y: heightNavigationBarTop + topSafeArea, width: view.frame.width, height: 50)
        lb.backgroundColor = .red
        return lb
    }()

    var collectionView: UICollectionView!
    var content = [Int: Any]()

    override func viewDidLoad() {
        super.viewDidLoad()
        loadContent()
        loadCollectionView()
        setLayout()
//        view.addSubview(label)
//        view.addSubview(collectionView)
    }

    func setLayout(){
        view.sv(label, collectionView)
        view.layout(
            heightNavigationBarTop,
            |-label-| ~ 80,
            0,
            |collectionView|,
            tabBarHeight
        )
    }

    func loadCollectionView() {
        let layout = UICollectionViewFlowLayout()
        let frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height)
        collectionView = UICollectionView(frame: frame, collectionViewLayout: layout)
        collectionView.backgroundColor = .white
        collectionView.register(CoinCVCCell.self, forCellWithReuseIdentifier: reUseIdentifierCollectionView)
        collectionView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0)
        if let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
            flowLayout.scrollDirection = .horizontal
            flowLayout.minimumLineSpacing = 0
        }
        collectionView.delegate   = self
        collectionView.dataSource = self
    }


    func loadContent() {
        content[0] = Content(name: "Blau", color: .blue)
        content[1] = Content(name: "Grün", color: .green)
        content[2] = Content(name: "Gelb", color: .yellow)
        content[3] = Content(name: "brown", color: .brown)
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

}

extension CVControllerViewController: UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 4
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let outputCell: UICollectionViewCell
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reUseIdentifierCollectionView, for: indexPath) as! CoinCVCCell
        cell.content = (content[indexPath.item] as! Content)
        outputCell = cell
        return outputCell
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 0
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let width = view.frame.width
        let height = view.frame.height - (tabBarHeight + label.frame.height + heightNavigationBarTop)

        let output = Utility.shared.CGSizeMake(width, height)
        return output
    }
}

我正在使用框架Stevia,基本上sv所做的是设置子视图并将“translatesAutoresizingMaskIntoConstraints”设置为false。 随着布局我设置约束,解决方案现在做我想要的但是你推荐的方式?

  

func collectionView(_ collectionView:UICollectionView,layout   collectionViewLayout:UICollectionViewLayout,sizeForItemAt indexPath:   IndexPath) - >

在这里我仍然使用框架,这有意义吗?

2 个答案:

答案 0 :(得分:2)

  

因为我从视图的总高度中减去视图上不同元素的高度

但是你知道视图的总高度。那就是问题所在。

您正在viewDidLoad中呼叫frame。这太早了,因为还没有任何正确的frame。因此,根据其他内容的frame计算集合视图的viewDidLayoutSubviews的所有计算都是错误的。

您可以等到loadCollectionView致电viewDidLoad来解决这个问题,但不要这样做。你根本不应该计算帧!相反,使用autolayout执行所有操作,并让autolayout引擎为您执行布局。这样,您就可以在frame中进行构建,而不会发现任何{{1}}值。

答案 1 :(得分:1)

以编程方式: 设置sectionInset并使布局无效

https://stackoverflow.com/a/35975792/6948184

OR

在集合视图的尺寸检查器中将部分插入设置为0为底部和顶部

ColectionView Section Inset