简体   繁体   English

iOS Swift - 水平扩展的固定高度的 CollectionView 或 TableView。有什么想法吗?

[英]iOS Swift - CollectionView or TableView with fixed height that expands horizontally .. Any Idea?

Hello dear developers!亲爱的开发者您好!

I hope somebody can help me.我希望有人能帮助我。

I'm looking for a way to create a TableView (ie a list with dynamic Sections and Rows) with a fixed height but dynamic width..我正在寻找一种方法来创建具有固定高度但动态宽度的 TableView(即具有动态部分和行的列表)。

Example: The TableView (or CollectionView) has a height of 600px, let's say 10 rows fit into the height.示例:TableView(或 CollectionView)的高度为 600px,假设 10 行适合该高度。 The 11th row should now not be below, but continue to the right..第 11 行现在不应该在下面,而是继续向右..

Below is a picture.下面是一张图片。

I really hope that someone can help me.. thank you in advance for reading.我真的希望有人能帮助我..提前感谢您的阅读。

PS: I invite the one with a solution for a coffee:b PS:我邀请有解决方案的人喝杯咖啡:b

->>> I think the picture shows clearly what I mean <<<- ->>> 我认为图片清楚地表达了我的意思<<<-

This could be done pretty straight-forward as a UICollectionView with a horizontal flow layout.这可以非常简单地完成,如UICollectionView和水平流布局。

  • Create one cell layout as the "Header" cell.创建一个单元格布局作为“标题”单元格。
  • Create a second cell layout as the "Detail" cell.创建第二个单元格布局作为“详细信息”单元格。
  • arrange your data to be a single section, with data elements identified as "header" or "detail"将您的数据安排为单个部分,数据元素标识为“标题”或“详细信息”

Quick example:快速示例:

enum MyCellType: Int {
    case header
    case detail
}
struct MyStruct {
    var type: MyCellType = .header
    var headerString: String = ""
    var detailString: String = ""
    var detailValue: String = ""
}
class TestViewController: UIViewController {
    var myData: [MyStruct] = []
    
    var collectionView: UICollectionView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .systemBlue
        
        // some sample data
        let headers: [String] = [
            "SOFTWARE", "BATTERY", "DEVICE", "HARDWARE", "MLB", "USAGE",
        ]
        let counts: [Int] = [
            4, 2, 7, 5, 1, 8,
        ]
        var val: Int = 1
        for (i, s) in headers.enumerated() {
            let t: MyStruct = MyStruct(type: .header, headerString: s, detailString: "", detailValue: "")
            myData.append(t)
            for j in 1...counts[i % counts.count] {
                let t: MyStruct = MyStruct(type: .detail, headerString: "", detailString: "Detail \(i),\(j)", detailValue: "Val: \(val)")
                myData.append(t)
                val += 1
            }
        }
    
        let fl = UICollectionViewFlowLayout()
        fl.scrollDirection = .horizontal
        fl.minimumLineSpacing = 12
        fl.minimumInteritemSpacing = 0
        fl.itemSize = CGSize(width: 200, height: 30)
        
        collectionView = UICollectionView(frame: .zero, collectionViewLayout: fl)
        collectionView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(collectionView)
        let g = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            collectionView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
            collectionView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
            collectionView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
            collectionView.heightAnchor.constraint(equalToConstant: 300.0),
        ])
        
        collectionView.register(MyHeaderCell.self, forCellWithReuseIdentifier: "headerCell")
        collectionView.register(MyDetailCell.self, forCellWithReuseIdentifier: "detailCell")
        
        collectionView.dataSource = self
        collectionView.delegate = self
    }
    
}

extension TestViewController: UICollectionViewDataSource, UICollectionViewDelegate {
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let t = myData[indexPath.item]
        if t.type == .header {
            let c = collectionView.dequeueReusableCell(withReuseIdentifier: "headerCell", for: indexPath) as! MyHeaderCell
            c.label.text = t.headerString
            return c
        }
        let c = collectionView.dequeueReusableCell(withReuseIdentifier: "detailCell", for: indexPath) as! MyDetailCell
        c.detailLabel.text = t.detailString
        c.valueLabel.text = t.detailValue
        // we don't want to show the "separator line" if the next
        //  item is a "header"
        if indexPath.item < myData.count - 1 {
            c.hideSepLine(myData[indexPath.item + 1].type == .header)
        }
        return c
    }
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return myData.count
    }
}

class MyHeaderCell: UICollectionViewCell {
    
    let label = UILabel()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    func commonInit() {
        label.translatesAutoresizingMaskIntoConstraints = false
        label.font = .systemFont(ofSize: 10, weight: .bold)
        contentView.addSubview(label)
        contentView.backgroundColor = UIColor(white: 0.9, alpha: 1.0)
        let g = contentView.layoutMarginsGuide
        NSLayoutConstraint.activate([
            label.topAnchor.constraint(equalTo: g.topAnchor, constant: 0.0),
            label.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
            label.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
            label.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0),
        ])
    }
}

class MyDetailCell: UICollectionViewCell {
    
    let detailLabel = UILabel()
    let valueLabel = UILabel()
    let sepLineView = UIView()

    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    func commonInit() {
        
        detailLabel.font = .systemFont(ofSize: 12.0, weight: .light)
        valueLabel.font = .systemFont(ofSize: 12.0, weight: .light)
        valueLabel.textColor = .gray

        sepLineView.backgroundColor = .lightGray
        
        [detailLabel, valueLabel, sepLineView].forEach { v in
            v.translatesAutoresizingMaskIntoConstraints = false
            contentView.addSubview(v)
        }

        let g = contentView.layoutMarginsGuide
        NSLayoutConstraint.activate([

            detailLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 16.0),
            detailLabel.centerYAnchor.constraint(equalTo: g.centerYAnchor),

            valueLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
            valueLabel.centerYAnchor.constraint(equalTo: g.centerYAnchor),

            sepLineView.leadingAnchor.constraint(equalTo: detailLabel.leadingAnchor),
            sepLineView.trailingAnchor.constraint(equalTo: valueLabel.trailingAnchor),
            sepLineView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
            sepLineView.heightAnchor.constraint(equalToConstant: 1.0),

        ])
        
    }
    
    func hideSepLine(_ b: Bool) {
        sepLineView.isHidden = b
    }
}

Results:结果:

在此处输入图像描述

scrolled a little to the left:向左滚动一点:

在此处输入图像描述

scrolled all the way to the left:一直向左滚动:

在此处输入图像描述

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

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