swift - 以编程方式将 collectionView 置于 View 中

标签 swift view uicollectionview programmatically-created

我想以编程方式在底部的导航栏、标签和标签栏之间放置一个 collectionView。

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

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 不适合空间,为什么会出现边距,因为我从 View 的总高度中减去 View 上不同元素的高度。

编辑:

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 所做的是设置 subview 并将“translatesAutoresizingMaskIntoConstraints”设置为 false。 通过布局设置约束,解决方案现在可以满足我的要求,但这是您推荐的方式吗?

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

我这里还是用frame,这样有意义吗?

最佳答案

because I subtract the height of the different elements on the view from the total height of the view

但是您不知道 View 的总高度。那就是问题所在。

您正在 viewDidLoad 中调用 loadCollectionView。那太早了,因为还没有正确的 frame。因此,您根据其他事物的 frame 计算 Collection View 的 frame 的所有计算都是不正确的。

您可以通过等到 viewDidLayoutSubviews 调用 loadCollectionView 来解决这个问题,但不要这样做。你根本不应该计算帧!相反,使用自动布局完成所有操作,让自动布局引擎为您完成布局。这样,您就可以在 viewDidLoad 中进行构造,而无需任何 frame 值发挥作用。

关于swift - 以编程方式将 collectionView 置于 View 中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49742156/

相关文章:

ios - 尝试使用 reloadsections 重新加载时部分中的行数无效

ios - iOS 中的 View 管理

ios - 在 Storyboard中设计 UICollectionViewCell

swift - UICollectionViewCells 未填充

objective-c - 动画 UICollectionView 单元格大小更改和重新定位周围单元格

swift - Collectionview 没有隐藏在 NavigationBar 下

ios - Firebase v3.2 iOS - 如何停止日志

swift - 使用 UserDefaults 更新数据模型

java if语句错误

Android View.OnKeyListener : click once, 执行两次