My view has a table view with a collection view on each row. The collection cells have a text field (well a subclass thereof), a label and a text view which are all full size and all but one are hidden depending on cell position.
When one of the text fields is edited the delegate (CollectionView) passes the new value back to the view controller to alter the array then the appropriate cells are reloaded as there is computed data in them.
The problem is the second time one of the text fields is edited two cells swap widths, it seems to swap back if you edit the text field two more times, but the border stays in the wrong position.
Table after initial load:
Table after changing quantity twice
text field and view delegate methods
func textFieldDidEndEditing(_ textField: UITextField) {
let currencyField = textField as! CurrencyField
let indexPath = indexPathForCellWithSubview(cellSubview: textField)!
(dataSource as! DetailViewController).changeData(tableRow: tag, collectionItem: indexPath.row, newData: currencyField.decimal)
let indexPaths: [IndexPath] = [IndexPath(row: 1, section: 0),IndexPath(row: 2, section: 0),IndexPath(row: 4, section: 0),IndexPath(row: 5, section: 0)]
collectionViewLayout.invalidateLayout()
reloadItems(at: indexPaths)
}
func textViewDidEndEditing(_ textView: UITextView) {
let indexPath = indexPathForCellWithSubview(cellSubview: textView)!
let indexPaths: [IndexPath] = [IndexPath(row: 1, section: 0),IndexPath(row: 2, section: 0),IndexPath(row: 4, section: 0),IndexPath(row: 5, section: 0)]
let dec = textView.text!.decimalFromString()
if(dec != 0){
(dataSource as! DetailViewController).changeData(tableRow: tag, collectionItem: indexPath.row, newData: dec)
reloadItems(at: indexPaths)
} else {
(dataSource as! DetailViewController).changeData(tableRow: tag, collectionItem: indexPath.row, newData: textView.text!)
}
collectionViewLayout.invalidateLayout()
}
Array
var dummyData: [[Any]] = [
["Fencing garden",Decimal(1),Decimal(8500.00)],
["Ditching",Decimal(1),Decimal(1950.00)],
["Fred",Decimal(1),Decimal(1950.00)]]
Cell widths
let table4Cells: [Int] = [310,65,100,105]
let table6Cells: [Int] = [250,40,80,50,80,80]
Data setting and getting
func changeData(tableRow: Int, collectionItem: Int, newData: Any){
var qty: Decimal = dummyData[tableRow][1] as! Decimal
var cost: Decimal = dummyData[tableRow][2] as! Decimal
var total: Decimal
switch(collectionItem){
case 1:
qty = newData as! Decimal
case 2:
cost = newData as! Decimal
case 3:
total = newData as! Decimal
cost = total / qty
case 5:
total = newData as! Decimal
cost = (total / qty) / (1 + vatPC)
default: dummyData[tableRow][collectionItem] = newData
}
dummyData[tableRow][1] = qty
dummyData[tableRow][2] = cost
}
func collectionViewCellText(tag: Int, row: Int) -> String {
var text: String = ""
if(tag == 666){
if(!vatRegistered && row == 3){
return tableHeaderText[5]
} else {
return tableHeaderText[row]
}
} else {
let qty: Decimal = dummyData[tag][1] as! Decimal
let cost: Decimal = dummyData[tag][2] as! Decimal
switch(row){
case 3:
if(vatRegistered){
text = String(describing: vatPC * 100)
} else {
text = String(describing: qty * cost)
}
case 4:
text = String(describing: cost * vatPC)
case 5:
text = String(describing: qty * (cost * (1 + vatPC)))
default:
text = String(describing: dummyData[tag][row])
}
}
return text
}
size for cell at indexpath
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
if(vatRegistered){
return CGSize(width: self.table6Cells[indexPath.row], height:self.collectionCellHeight)
}
return CGSize(width: self.table4Cells[indexPath.row], height:self.collectionCellHeight)
}
cell for row at index path
func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell",
for: indexPath as IndexPath) as! InvoiceCollectionViewCell
cell.textView.delegate = self
if(collectionView is RJCollectionView){
cell.currencyField.delegate = collectionView as! RJCollectionView
cell.textView.delegate = collectionView as! RJCollectionView
}
if(collectionView.tag == 666){
if(indexPath.row == 0){
cell.addBorder(side: .left, thickness: 0.5, color: UIColor.black)
cell.addBorder(side: .right, thickness: 0.5, color: UIColor.black)
cell.addBorder(side: .top, thickness: 0.5, color: UIColor.black)
cell.addBorder(side: .bottom, thickness: 0.5, color: UIColor.black)
} else {
cell.label.textAlignment = NSTextAlignment.center
cell.textView.textAlignment = NSTextAlignment.center
cell.addBorder(side: .right, thickness: 0.5, color: UIColor.black)
cell.addBorder(side: .top, thickness: 0.5, color: UIColor.black)
cell.addBorder(side: .bottom, thickness: 0.5, color: UIColor.black)
}
} else {
if(indexPath.row == 0){
cell.addBorder(side: .left, thickness: 0.5, color: UIColor.black)
cell.addBorder(side: .right, thickness: 0.5, color: UIColor.black)
cell.addBorder(side: .bottom, thickness: 0.5, color: UIColor.black)
} else {
cell.label.textAlignment = NSTextAlignment.center
cell.textView.textAlignment = NSTextAlignment.center
cell.addBorder(side: .right, thickness: 0.5, color: UIColor.black)
cell.addBorder(side: .bottom, thickness: 0.5, color: UIColor.black)
}
if(vatRegistered){
switch(indexPath.row){
case 2,5: cell.textType(i: "CurrencyView")
case 3:
cell.textType(i: "TextView")
cell.textView.isUserInteractionEnabled = false
case 4:
cell.currencyField.isUserInteractionEnabled = false
cell.textType(i: "CurrencyView")
default: cell.textType(i: "TextView")
}
} else {
switch(indexPath.row){
case 2,3: cell.textType(i: "CurrencyView")
default: cell.textType(i: "TextView")
}
}
}
if(collectionView.tag == 0){
print(cell.currencyField.bounds.width)
}
cell.text = collectionViewCellText(tag: collectionView.tag, row: indexPath.row)
return cell
}
NB: collectionview.tag is the row on the table the collection view is in. 666 is the header row. vatRegistered is a bool that when true sets width of collection view to 6 rather than 4 cells
Update:
I stripped out my whole project into a secondary project and put the collectionview directly into the main view, but still had the issue
It seems the issue was being caused by the contentView not resizing to the size of the cell, which appears to be a bug with iOS so when the cells were pushed and popped onto the stack on reload they switched order, but for whatever reason setting the cell size didn't reset the size of the contentView.
adding:
cell.contentView.frame = cell.bounds;
cell.contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
to the sizeforitem flow layout method fixed the weird offsets.
the border in the wrong place is down to the uiview extension i use to add the borders, it just adds a view of a set width to whichever edge it's asked to, this has to be removed when reusing the cells