Stuck entendiendo cómo crear una tabla con múltiples columnas en iOS Swift

He pasado la mejor parte del día hasta ahora investigando e intentando entender cómo hacer una tabla con múltiples columnas. Sinceramente, todavía soy bastante nuevo en Swift y en la progtwigción en general, así que muchas de las cosas que he leído y encontrado no me están ayudando demasiado.

Básicamente he encontrado exactamente lo que quiero crear con este caballero blo: http://www.brightec.co.uk/blog/uicollectionview-using-horizontal-and-vertical-scrolling-sticky-rows-and-columns

Sin embargo, incluso con su Github todavía estoy confundido. Parece como si él no usara Storyboard en absoluto (y para mi proyecto he estado usando mucho storyboard). ¿Estoy en lo cierto al suponer esto?

Lo que tengo hasta ahora es una UICollectionView incrustada en un controller de navigation. Desde aquí, he creado un nuevo file de class táctil de cocoa subclasificado en CollectionView. Pero desde aquí es donde no estoy del todo seguro de dónde ir.

Si puedo tener alguna orientación sobre a dónde ir desde aquí o cómo configurarla correctamente, sería GRANAMENTE apreciada.

Muchas gracias de antemano!

Un enfoque es utilizar una celda personalizada en un tableviewcontroller. Su tablero de historia consiste en una tabla en la cual la celda es una celda personalizada con UILabels para columnas dispuestas una junto a la otra (con restricciones apropiadamente definidas).

El código de ejemplo para los controlleres se ve así:

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 (eg from an array) cell.column2.text = "2" // fill in your value for column 2 return cell } } 

y:

 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 } } 

IOS 10, XCode 8, Swift 3.0

Encontré un impresionante tutorial sobre esto. gracias a Kyle Andrews

Creé una tabla vertical que se puede desplazar en ambas direcciones subclassando UICollectionViewLayout. A continuación se muestra el código.

  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.shanetworking.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 } } 

A continuación se muestra mi código CollectionViewController.

  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 } } 

Para obligar a CollectionView a utilizar Diseño personalizado en lugar de UICollectionViwFlowLayout, verifique la image siguiente.

introduzca la descripción de la imagen aquí

Resultado:

Modo retrato

introduzca la descripción de la imagen aquí

Modo paisaje

introduzca la descripción de la imagen aquí

En IB, configuré una vista de tabla y agregué una vista de stack en la vista de contenido (se puede hacer mediante progtwigción). Las tags se configuran mediante progtwigción, ya que me permite establecer el ancho de cada columna como una fracción del ancho de la celda. Además, reconozco que algunos de los cálculos dentro del método view cellForRow de la tabla deben ser eliminados.

  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 } }