Stuck understanding how to create a table with multiple columns in iOS Swift

自闭症网瘾萝莉.ら 提交于 2019-12-03 07:30:33

问题


I've spent the better half of the day so far researching and trying to understand how to make a table with multiple columns. Embarrassingly, I am still quite new to Swift and programming in general so a lot of the stuff I've read and found aren't helping me too much.

I have basically found exactly what I want to create with this gentleman's blo: http://www.brightec.co.uk/blog/uicollectionview-using-horizontal-and-vertical-scrolling-sticky-rows-and-columns

However, even with his Github I'm still confused. It seems as if he did not use Storyboard at all (and for my project I've been using storyboard a lot). Am I correct in assuming this?

What I have so far is a UICollectionView embedded in a navigation controller. From here, I have created a new cocoa touch class file subclassed in the CollectionView. But from here is where I'm not entirely sure where to go.

If I can have some direction as to where to go from here or how to properly set it up that would be GREATLY appreciated.

Thanks so much in advance!


回答1:


One approach is to use a custom cell in a tableviewcontroller. Your story board consists of a table in which the cell is a custom cell with UILabels for columns laid out next to each other (with properly defined constraints).

Example code for the controllers looks like:

import UIKit

class TableViewController: UITableViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    // MARK: - Table view data source

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        return 3
    }


    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("reuseIdentifier", forIndexPath: indexPath) as TableViewCell
        cell.column1.text = "1" // fill in your value for column 1 (e.g. from an array)
        cell.column2.text = "2" // fill in your value for column 2

        return cell
    }

}

and:

import UIKit

class TableViewCell: UITableViewCell {

    @IBOutlet weak var column1: UILabel!
    @IBOutlet weak var column2: UILabel!
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

}



回答2:


IOS 10, XCode 8, Swift 3.0

I found an awesome tutorial on this. thanks to Kyle Andrews

I created a vertical table which can be scrollable on both directions by subclassing UICollectionViewLayout. Below is the code.

 class CustomLayout: UICollectionViewLayout {

    let CELL_HEIGHT: CGFloat = 50
    let CELL_WIDTH: CGFloat = 180


    var cellAttributesDictionary = Dictionary<IndexPath, UICollectionViewLayoutAttributes>()
    var contentSize = CGSize.zero

    override var collectionViewContentSize: CGSize {
        get {
            return contentSize
        }
    }

    var dataSourceDidUpdate = true

    override func prepare() {

        let STATUS_BAR_HEIGHT = UIApplication.shared.statusBarFrame.height
        let NAV_BAR_HEIGHT = UINavigationController().navigationBar.frame.size.height

        collectionView?.bounces = false

        if !dataSourceDidUpdate {

            let yOffSet = collectionView!.contentOffset.y

            for section in 0 ..< collectionView!.numberOfSections {
                if section == 0 {
                    for item in 0 ..< collectionView!.numberOfItems(inSection: section) {
                        let cellIndexPath = IndexPath(item: item, section: section)
                        if let attrs = cellAttributesDictionary[cellIndexPath] {
                            var frame = attrs.frame
                            frame.origin.y = yOffSet + STATUS_BAR_HEIGHT + NAV_BAR_HEIGHT
                            attrs.frame = frame
                        }
                    }
                }
            }
           return
        }

        dataSourceDidUpdate = false

        for section in 0 ..< collectionView!.numberOfSections {
            for item in 0 ..< collectionView!.numberOfItems(inSection: section) {
                let cellIndexPath = IndexPath(item: item, section: section)
                let xPos = CGFloat(item) * CELL_WIDTH
                let yPos = CGFloat(section) * CELL_HEIGHT

                let cellAttributes = UICollectionViewLayoutAttributes(forCellWith: cellIndexPath)
                cellAttributes.frame = CGRect(x: xPos, y: yPos, width: CELL_WIDTH, height: CELL_HEIGHT)

                // Determine zIndex based on cell type.
                if section == 0 && item == 0 {
                    cellAttributes.zIndex = 4
                } else if section == 0 {
                    cellAttributes.zIndex = 3
                } else if item == 0 {
                    cellAttributes.zIndex = 2
                } else {
                    cellAttributes.zIndex = 1
                }

                cellAttributesDictionary[cellIndexPath] = cellAttributes

            }
        }

        let contentWidth = CGFloat(collectionView!.numberOfItems(inSection: 0)) * CELL_WIDTH
        let contentHeight = CGFloat(collectionView!.numberOfSections) * CELL_HEIGHT
        contentSize = CGSize(width: contentWidth, height: contentHeight)
    }

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        var attributesInRect = [UICollectionViewLayoutAttributes]()

        for cellAttrs in cellAttributesDictionary.values {
            if rect.intersects(cellAttrs.frame) {
                attributesInRect.append(cellAttrs)
            }
        }

        return attributesInRect
    }

    override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        return cellAttributesDictionary[indexPath]
    }

    override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
        return true
    }
}

Below is my CollectionViewController Code.

    import UIKit

private let reuseIdentifier = "Cell"

class VerticalCVC: UICollectionViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        collectionView?.isScrollEnabled = true
    }

    // MARK: UICollectionViewDataSource

    override func numberOfSections(in collectionView: UICollectionView) -> Int {

        return 20
    }


    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 10
    }

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! CustomCell

        if indexPath.section == 0 {
            cell.backgroundColor = UIColor.darkGray
            cell.titleLabel.textColor = UIColor.white


        } else {
            cell.backgroundColor = UIColor.white
            cell.titleLabel.textColor = UIColor.black
        }

        cell.titleLabel.text = "section: \(indexPath.section) && row: \(indexPath.row)"

        return cell
    }
}

To force CollectionView to use Custom Layout instead of UICollectionViwFlowLayout check below image.

Result:

Portrait mode

landscape mode




回答3:


In IB I set up a tableview and added a stackview in the content view (can be done programmatically). The labels are setup programmatically since it allows me to set the width of each column as a fraction of the cell width. Also, I acknowledge that some of the calculations inside the table view cellForRow method should be moved out.

 import UIKit

class tableViewController: UITableViewController {
var firstTime = true
var width = CGFloat(0.0)
var height = CGFloat(0.0)
var cellRect = CGRectMake(0.0,0.0,0.0,0.0)

let colors:[UIColor] = [
    UIColor.greenColor(),
    UIColor.yellowColor(),
    UIColor.lightGrayColor(),
    UIColor.blueColor(),
    UIColor.cyanColor()
]

override func viewDidLoad() {
    super.viewDidLoad()
// workaround to get the cell width 
    cellRect = CGRectMake(0, 0, self.tableView.frame.size.width ,44);
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()

}

// MARK: - Table view data source

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return 3
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 1
}

var cellWidth = CGFloat(0.0)
var cellHeight = CGFloat(0.0)
let widths = [0.2,0.3,0.3,0.2]
let labels = ["0","1","2","3"]

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
        let v = cell.contentView.subviews[0] // points to stack view
        // Note: using w = v.frame.width picks up the width assigned by xCode.
        cellWidth = cellRect.width-20.0 // work around to get a right width
        cellHeight = cellRect.height

        var x:CGFloat = 0.0
        for i in 0 ..< labels.count {
            let wl = cellWidth * CGFloat(widths[i])
            let lFrame = CGRect(origin:CGPoint(x: x,y: 0),size: CGSize(width:wl,height: cellHeight))
            let label = UILabel(frame: lFrame)
            label.textAlignment = .Center
            label.text = labels[i]
            v.addSubview(label)
            x = x + wl
            print("i = ",i,v.subviews[i])
            v.subviews[i].backgroundColor = colors[i]
        }


    return cell
}


}


来源:https://stackoverflow.com/questions/29334978/stuck-understanding-how-to-create-a-table-with-multiple-columns-in-ios-swift

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!