Related
i am facing a very strange bug in my tableView. When changing the row height, the content gets mixed up very strangely (see the GIF).
Here is the code for my tableView, I think I have all labels, imageViews etc. properly resetted at the beginning. I added the Task # MainAnchor method but it didnt change anything.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "detailVerbindungTableViewCell", for: indexPath) as! detailVerbindungTableViewCell
Task { #MainActor in
for view in cell.contentView.subviews {
if let label = view as? LineHalfTriangleView {
label.removeFromSuperview()
}
}
for view in cell.sideLineView.subviews {
cell.sideLineView.willRemoveSubview(view)
}
var arrayIndex = indexPath.row / 2
print(arrayIndex)
let middleSeperator = UIView(frame: CGRect(x: 0, y: cell.contentView.frame.height / 2, width: cell.contentView.frame.width, height: 1))
middleSeperator.backgroundColor = UIColor.systemBlue
var sideLineType = "end"
let timeFormatHHMM = DateFormatter()
timeFormatHHMM.timeStyle = .short
var sideColor = UIColor.clear
var sideTopColor = UIColor.clear
var sideBottomColor = UIColor.clear
cell.devLabel.text = "\(arrayIndex)"
cell.devLabel.isHidden = !UserDefaults.standard.bool(forKey: "devDetailVerbIndex")
cell.lineNumberLabel.text = ""
cell.lineNumberLabel.textColor = .label
cell.lineNumberLabel.backgroundColor = .clear
cell.destinationLabel.text = ""
cell.timeBottomLabel.text = ""
cell.timeMiddleLabel.text = ""
cell.timeTopLabel.text = ""
cell.constDestToNumber.constant = 8
cell.constDestToStrich.constant = 58
cell.constDestToNumber.isActive = true
cell.destinationLabel.font = UIFont.systemFont(ofSize: cell.destinationLabel.font.pointSize)
cell.timeTopLabel.textColor = UIColor.label
cell.timeMiddleLabel.textColor = UIColor.label
cell.timeBottomLabel.textColor = UIColor.label
if indexPath.row % 2 == 0 {
//Location cell
cell.contentView.backgroundColor = UIColor.systemBackground
cell.constDestToNumber.isActive = false
cell.constDestToStrich.constant = 8
cell.destinationLabel.font = UIFont.systemFont(ofSize: cell.destinationLabel.font.pointSize, weight: .semibold)
if arrayIndex == resultLegArray[selectedIndex][0].count {
cell.destinationLabel.text = resultLegArray[selectedIndex][0].last?.arrival.name
} else {
cell.destinationLabel.text = resultLegArray[selectedIndex][0][arrayIndex].departure.name
}
if arrayIndex == resultLegArray[selectedIndex][0].count {
//Location cell
//Show Time
//Last cell
sideLineType = "end"
cell.timeTopLabel.isHidden = true
cell.timeMiddleLabel.isHidden = false
cell.timeBottomLabel.isHidden = true
if resultLegArray[selectedIndex][0].last is PublicLeg {
print("PublicLeg")
var tempPublicLeg = resultLegArray[selectedIndex][0].last as! PublicLeg
if tempPublicLeg.arrivalTime == tempPublicLeg.plannedArrivalTime {
cell.timeMiddleLabel.text = timeFormatHHMM.string(from: tempPublicLeg.plannedArrivalTime)
cell.timeMiddleLabel.textColor = UIColor.systemGreen
} else {
let timeDifference = tempPublicLeg.plannedArrivalTime.distance(to: tempPublicLeg.arrivalTime )
cell.timeMiddleLabel.text = timeFormatHHMM.string(from: tempPublicLeg.arrivalTime)
cell.timeMiddleLabel.textColor = UIColor.systemRed
if timeDifference.stringFromTimeIntervalOnlyNumber().contains("-") == true {
cell.timeMiddleLabel.textColor = UIColor.systemBlue
}
}
sideColor = UIColor(argb: tempPublicLeg.line.style.backgroundColor)
} else {
print("IndividualLeg")
var tempIndLeg = resultLegArray[selectedIndex][0].last as! IndividualLeg
cell.timeMiddleLabel.text = timeFormatHHMM.string(from: tempIndLeg.arrivalTime)
cell.timeMiddleLabel.textColor = UIColor.label
sideColor = UIColor.lightGray
}
} else {
//Not last cell
//Location cell
//Show Time
if arrayIndex == 0 {
sideLineType = "start"
cell.timeTopLabel.isHidden = true
cell.timeMiddleLabel.isHidden = false
cell.timeBottomLabel.isHidden = true
if resultLegArray[selectedIndex][0].first?.departureTime == resultLegArray[selectedIndex][0].first?.plannedDepartureTime {
cell.timeMiddleLabel.text = timeFormatHHMM.string(from: resultLegArray[selectedIndex][0].first!.plannedDepartureTime)
cell.timeMiddleLabel.textColor = UIColor.systemGreen
} else {
let timeDifference = resultLegArray[selectedIndex][0].first?.plannedDepartureTime.distance(to: (resultLegArray[selectedIndex][0].first?.departureTime ?? resultLegArray[selectedIndex][0].first?.plannedDepartureTime)!)
cell.timeMiddleLabel.text = timeFormatHHMM.string(from: resultLegArray[selectedIndex][0].first!.departureTime)
cell.timeMiddleLabel.textColor = UIColor.systemRed
if timeDifference?.stringFromTimeIntervalOnlyNumber().contains("-") == true {
cell.timeMiddleLabel.textColor = UIColor.systemBlue
}
}
//MARK: Location middle Side Color
if resultLegArray[selectedIndex][0][arrayIndex] is PublicLeg {
print("PublicLeg")
var tempPublicLeg = resultLegArray[selectedIndex][0][arrayIndex] as! PublicLeg
sideColor = UIColor(argb: tempPublicLeg.line.style.backgroundColor)
} else {
print("IndividualLeg")
var tempIndLeg = resultLegArray[selectedIndex][0][arrayIndex] as! IndividualLeg
sideColor = UIColor.lightGray
}
} else {//MARK: sideLineType Middle
sideLineType = "middle"
cell.timeTopLabel.isHidden = false
cell.timeMiddleLabel.isHidden = true
cell.timeBottomLabel.isHidden = false
if resultLegArray[selectedIndex][0][arrayIndex].departureTime == resultLegArray[selectedIndex][0][arrayIndex].plannedDepartureTime {
cell.timeBottomLabel.text = timeFormatHHMM.string(from: resultLegArray[selectedIndex][0][arrayIndex].departureTime)
cell.timeBottomLabel.textColor = UIColor.systemGreen
} else {
let timeDifference = resultLegArray[selectedIndex][0][arrayIndex].plannedDepartureTime.distance(to: resultLegArray[selectedIndex][0][arrayIndex].departureTime )
cell.timeBottomLabel.text = timeFormatHHMM.string(from: resultLegArray[selectedIndex][0][arrayIndex].departureTime)
cell.timeBottomLabel.textColor = UIColor.systemRed
if timeDifference.stringFromTimeIntervalOnlyNumber().contains("-") == true {
cell.timeBottomLabel.textColor = UIColor.systemBlue
}
}
if resultLegArray[selectedIndex][0][arrayIndex-1].arrivalTime == resultLegArray[selectedIndex][0][arrayIndex-1].plannedArrivalTime {
cell.timeTopLabel.text = timeFormatHHMM.string(from: resultLegArray[selectedIndex][0][arrayIndex-1].arrivalTime)
cell.timeTopLabel.textColor = UIColor.systemGreen
} else {
let timeDifference = resultLegArray[selectedIndex][0][arrayIndex-1].plannedArrivalTime.distance(to: resultLegArray[selectedIndex][0][arrayIndex-1].arrivalTime )
cell.timeTopLabel.text = timeFormatHHMM.string(from: resultLegArray[selectedIndex][0][arrayIndex-1].arrivalTime)
cell.timeTopLabel.textColor = UIColor.systemRed
if timeDifference.stringFromTimeIntervalOnlyNumber().contains("-") == true {
cell.timeTopLabel.textColor = UIColor.systemBlue
}
}
if resultLegArray[selectedIndex][0][arrayIndex] is PublicLeg {
print("PublicLeg")
var tempPublicLeg = resultLegArray[selectedIndex][0][arrayIndex] as! PublicLeg
sideBottomColor = UIColor(argb: tempPublicLeg.line.style.backgroundColor)
} else {
print("IndividualLeg")
var tempIndLeg = resultLegArray[selectedIndex][0][arrayIndex] as! IndividualLeg
sideBottomColor = UIColor.lightGray
}
if resultLegArray[selectedIndex][0][arrayIndex-1] is PublicLeg { //Line before current
print("PublicLeg")
var tempPublicLeg = resultLegArray[selectedIndex][0][arrayIndex-1] as! PublicLeg
sideTopColor = UIColor(argb: tempPublicLeg.line.style.backgroundColor)
} else {
print("IndividualLeg")
var tempIndLeg = resultLegArray[selectedIndex][0][arrayIndex-1] as! IndividualLeg
sideTopColor = UIColor.lightGray
}
}
}
//Even index
} else {
//Info cell
cell.timeTopLabel.isHidden = true
cell.timeMiddleLabel.isHidden = true
cell.timeBottomLabel.isHidden = true
sideLineType = "static"
cell.backgroundColor = UIColor.systemBackground
if resultLegArray[selectedIndex][0][arrayIndex] is PublicLeg {
//Fahrzeug
print("PublicLeg")
var tempPublicLeg = resultLegArray[selectedIndex][0][arrayIndex] as! PublicLeg
cell.lineNumberLabel.text = tempPublicLeg.line.label ?? ""
cell.destinationLabel.text = tempPublicLeg.destination?.name
if tempPublicLeg.line.style.backgroundColor2 == nil || tempPublicLeg.line.style.backgroundColor2 == 0 {
cell.lineNumberLabel.backgroundColorC = tempPublicLeg.line.style.backgroundColor
} else {
cell.lineNumberLabel.backgroundColorC = UInt32(UIColor.clear.hexa)
let backgroundLineHalfHalf = LineHalfTriangleView(frame: cell.lineNumberLabel.frame)
backgroundLineHalfHalf.topColor = tempPublicLeg.line.style.backgroundColor
backgroundLineHalfHalf.bottomColor = tempPublicLeg.line.style.backgroundColor2
backgroundLineHalfHalf.borderColor = tempPublicLeg.line.style.borderColor
cell.contentView.addSubview(backgroundLineHalfHalf)
cell.contentView.sendSubviewToBack(backgroundLineHalfHalf)
}
cell.lineNumberLabel.foregroundColor = tempPublicLeg.line.style.foregroundColor
cell.lineNumberLabel.roundCorners(corners: .allCorners, radius: 0)
//MARK: Info PublicLeg Time
if tempPublicLeg.departureTime == tempPublicLeg.plannedDepartureTime {
} else {
let timeDifference = tempPublicLeg.plannedDepartureTime.distance(to: tempPublicLeg.departureTime )
cell.timeTopLabel.text = timeDifference.stringFromTimeIntervalWithText()
cell.timeTopLabel.textColor = UIColor.systemRed
cell.timeTopLabel.isHidden = false
cell.timeTopLabel.text = "+ \(timeDifference.stringFromTimeIntervalOnlyNumber())"
if cell.timeTopLabel.text?.contains("-") == true {
cell.timeTopLabel.text = cell.timeTopLabel.text?.replacingOccurrences(of: "+ ", with: "")
cell.timeTopLabel.text = cell.timeTopLabel.text?.replacingOccurrences(of: "-", with: "- ")
cell.timeTopLabel.textColor = UIColor.systemBlue
}
}
if tempPublicLeg.arrivalTime == tempPublicLeg.plannedArrivalTime {
} else {
let timeDifference = tempPublicLeg.plannedArrivalTime.distance(to: tempPublicLeg.arrivalTime )
cell.timeBottomLabel.text = timeDifference.stringFromTimeIntervalWithText()
cell.timeBottomLabel.textColor = UIColor.systemRed
cell.timeBottomLabel.isHidden = false
cell.timeBottomLabel.text = "+ \(timeDifference.stringFromTimeIntervalOnlyNumber())"
if cell.timeBottomLabel.text?.contains("-") == true {
cell.timeBottomLabel.text = cell.timeBottomLabel.text?.replacingOccurrences(of: "+ ", with: "")
cell.timeBottomLabel.text = cell.timeBottomLabel.text?.replacingOccurrences(of: "-", with: "- ")
cell.timeBottomLabel.textColor = UIColor.systemBlue
}
}
if cell.timeTopLabel.text == cell.timeBottomLabel.text {
cell.timeTopLabel.isHidden = true
cell.timeBottomLabel.isHidden = true
cell.timeMiddleLabel.isHidden = false
cell.timeMiddleLabel.text = cell.timeTopLabel.text
cell.timeMiddleLabel.textColor = cell.timeTopLabel.textColor
}
sideColor = UIColor(argb: tempPublicLeg.line.style.backgroundColor)
cell.lineNumberLabel.shape = tempPublicLeg.line.style.shape
//Expandable Cell
let intermediateTableView = UITableView(frame: CGRect(x: 0, y: cell.frame.height, width: cell.frame.width, height: 30))
intermediateTableView.register(detailVerbindungIntermediateStopTableViewCell.self, forCellReuseIdentifier: "detailVerbindungIntermediateStopTableViewCell")
intermediateTableView.dataSource = cell
intermediateTableView.delegate = cell
cell.contentView.addSubview(intermediateTableView)
} else {
//Walk
print("IndividualLeg")
var tempIndLeg = resultLegArray[selectedIndex][0][arrayIndex] as! IndividualLeg
cell.destinationLabel.text = "Fußweg: \(tempIndLeg.departure.getDistanceText(CLLocation(latitude: CLLocationDegrees(tempIndLeg.arrival.coord?.lat ?? 0)/1000000, longitude: CLLocationDegrees(tempIndLeg.arrival.coord?.lon ?? 0)/1000000)))"
let config = UIImage.SymbolConfiguration(paletteColors: [.label, .lightGray])
let walkIconImgView = UIImageView(frame: CGRect(x: 96, y: 24, width: 42, height: 42))
walkIconImgView.contentMode = .scaleAspectFit
walkIconImgView.image = UIImage(systemName: "figure.walk.diamond")!.applyingSymbolConfiguration(config)
cell.addSubview(walkIconImgView)
walkIconImgView.isHidden = true
let imageAttachment = NSTextAttachment()
imageAttachment.image = UIImage(systemName: "figure.walk", withConfiguration: config)
let fullString = NSMutableAttributedString(string: "")
fullString.append(NSAttributedString(attachment: imageAttachment))
cell.lineNumberLabel.attributedText = fullString
sideColor = UIColor.lightGray
}
}
switch sideLineType {
case "middle": // ⎡ Comes from bottom to top
// Create the ⏐ UIView
let leftView = UIView()
leftView.frame = CGRect(x: 0, y: cell.sideLineView.frame.height / 2 + 7, width: 6, height: cell.sideLineView.frame.height / 2)
leftView.backgroundColor = sideBottomColor
// Create the ⎯ UIView
let rightView = UIView()
rightView.frame = CGRect(x: 0, y: cell.sideLineView.frame.height / 2 + 7, width: cell.sideLineView.frame.width, height: 6)
rightView.backgroundColor = sideBottomColor
// Add the subviews to the container view
cell.sideLineView.addSubview(leftView)
cell.sideLineView.addSubview(rightView)
// ⎣ Comes from top to bottom
// Create the ⏐ UIView
let topLeftView = UIView()
topLeftView.frame = CGRect(x: 0, y: 0, width: 6, height: cell.sideLineView.frame.height / 2 - 11)
topLeftView.backgroundColor = sideTopColor
// Create the ⎯ UIView
let topRightView = UIView()
topRightView.frame = CGRect(x: 0, y: cell.sideLineView.frame.height / 2 - 11, width: cell.sideLineView.frame.width, height: 6)
topRightView.backgroundColor = sideTopColor
// Add the subviews to the container view
cell.sideLineView.addSubview(topLeftView)
cell.sideLineView.addSubview(topRightView)
case "start": // ⎡
let sideLineMainView = UIView(frame: CGRect(x: 0, y: cell.sideLineView.frame.height / 2 - 3, width: 6, height: cell.sideLineView.frame.height))
sideLineMainView.backgroundColor = sideColor
cell.sideLineView.addSubview(sideLineMainView)
let sideLineSideView = UIView(frame: CGRect(x: 0, y: cell.sideLineView.frame.height / 2 - 3, width: cell.sideLineView.frame.width, height: 6))
sideLineSideView.backgroundColor = sideColor
cell.sideLineView.addSubview(sideLineSideView)
case "end": // ⎣
let sideLineMainView = UIView(frame: CGRect(x: 0, y: 0, width: 6, height: cell.sideLineView.frame.height / 2 + 3))
sideLineMainView.backgroundColor = sideColor
cell.sideLineView.addSubview(sideLineMainView)
let sideLineSideView = UIView(frame: CGRect(x: 0, y: cell.sideLineView.frame.height / 2 - 3, width: cell.sideLineView.frame.width, height: 6))
sideLineSideView.backgroundColor = sideColor
cell.sideLineView.addSubview(sideLineSideView)
case "static": // ⎥
let sideLineMainView = UIView(frame: CGRect(x: 0, y: 0, width: 6, height: cell.sideLineView.frame.height))
sideLineMainView.backgroundColor = sideColor
cell.sideLineView.addSubview(sideLineMainView)
default: break
}
}
return cell
}
And with the following method, I change the height:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if expandedRowIndex == indexPath.row {
expandedRowIndex = -1
shouldExpanded = false
} else {
expandedRowIndex = indexPath.row
shouldExpanded = true
}
tableView.reloadRows(at: [indexPath], with: .automatic)
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row == expandedRowIndex && shouldExpanded == true {
return 91 //Expanded
}
return 71 //Not expanded
}
Thanks in advance and sorry for my bad English ;)
We're missing a lot of information - data structures, sample data, etc. - so I can't copy/paste/run your code to figure out exactly what's wrong.
However, I would strongly suggest:
process your data in your data structure (calculating time differences, etc)
put your "cell layout" code inside your cell class(es), not inside cellForRowAt
don't add/remove subviews inside cellForRowAt
use auto-layout / constraints rather than calculating sizes
and, what I think would really help you...
use multiple cell classes
For example, instead of ONE cell class that needs add/remove subviews for every instance, use four classes (I don't know what your ultimate needs will be, so you might need more). I've added vertical space between the cells to make it clear:
Now, in each cell's init process, create and layout only the UI elements that cell will need.
Then, in cellForRowAt, dequeue and configure the appropriate class.
Here's how it would look without the inter-cell spacing:
If that's not quite clear, or if you're still having trouble... if you put together a minimal reproducible example (post it somewhere like GitHub) that includes your data structures and some sample data and I can help you find the issue.
Update:
Thank you very much for you comments, I appreciate it!
To the last comment, this is how my cells should look like/look now:
The data I get comes from a private API Server of the Deutsche Bahn. I've updated my code and now this is my cellForRowAt method:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "detailVerbindungTableViewCell", for: indexPath) as! detailVerbindungTableViewCell
Task { #MainActor in
for view in cell.contentView.subviews {
if let label = view as? LineHalfTriangleView {
label.removeFromSuperview()
}
}
for view in cell.sideLineView.subviews {
cell.sideLineView.willRemoveSubview(view)
}
var arrayIndex = indexPath.row / 2
print(arrayIndex)
let middleSeperator = UIView(frame: CGRect(x: 0, y: cell.contentView.frame.height / 2, width: cell.contentView.frame.width, height: 1))
middleSeperator.backgroundColor = UIColor.systemBlue
var sideLineType = "end"
var sideColor = UIColor.clear
var sideTopColor = UIColor.clear
var sideBottomColor = UIColor.clear
cell.devLabel.text = "\(arrayIndex)"
cell.devLabel.isHidden = !UserDefaults.standard.bool(forKey: "devDetailVerbIndex")
cell.lineNumberLabel.text = ""
cell.lineNumberLabel.textColor = .label
cell.lineNumberLabel.backgroundColor = .clear
cell.intermediateStops.removeAll()
cell.destinationLabel.text = ""
cell.timeBottomLabel.text = ""
cell.timeMiddleLabel.text = ""
cell.timeTopLabel.text = ""
cell.constDestToNumber.constant = 8
cell.constDestToStrich.constant = 58
cell.constDestToNumber.isActive = true
cell.destinationLabel.font = UIFont.systemFont(ofSize: cell.destinationLabel.font.pointSize)
cell.timeTopLabel.textColor = UIColor.label
cell.timeMiddleLabel.textColor = UIColor.label
cell.timeBottomLabel.textColor = UIColor.label
if indexPath.row % 2 == 0 {
//Location cell
cell.contentView.backgroundColor = UIColor.systemBackground
cell.constDestToNumber.isActive = false
cell.constDestToStrich.constant = 8
cell.destinationLabel.font = UIFont.systemFont(ofSize: cell.destinationLabel.font.pointSize, weight: .semibold)
if arrayIndex == resultLegArray[selectedIndex][0].count {
cell.destinationLabel.text = resultLegArray[selectedIndex][0].last?.arrival.name
} else {
cell.destinationLabel.text = resultLegArray[selectedIndex][0][arrayIndex].departure.name
}
if arrayIndex == resultLegArray[selectedIndex][0].count {
//Location cell
//Show Time
//Last cell
sideLineType = "end"
cell.timeTopLabel.isHidden = true
cell.timeMiddleLabel.isHidden = false
cell.timeBottomLabel.isHidden = true
if resultLegArray[selectedIndex][0].last is PublicLeg {
print("PublicLeg")
var tempPublicLeg = resultLegArray[selectedIndex][0].last as! PublicLeg
if tempPublicLeg.arrivalStop.predictedTime == nil {
cell.timeMiddleLabel.text = timeFormatHHMM.string(from: tempPublicLeg.plannedArrivalTime)
cell.timeMiddleLabel.textColor = UIColor.label
} else if tempPublicLeg.arrivalStop.plannedTime == tempPublicLeg.arrivalStop.predictedTime {
cell.timeMiddleLabel.text = timeFormatHHMM.string(from: tempPublicLeg.plannedArrivalTime)
cell.timeMiddleLabel.textColor = UIColor.systemGreen
} else {
let timeDifference = tempPublicLeg.plannedArrivalTime.distance(to: tempPublicLeg.arrivalTime )
cell.timeMiddleLabel.text = timeFormatHHMM.string(from: tempPublicLeg.arrivalTime)
cell.timeMiddleLabel.textColor = UIColor.systemRed
if timeDifference.stringFromTimeIntervalOnlyNumber().contains("-") == true {
cell.timeMiddleLabel.textColor = UIColor.systemBlue
}
}
sideColor = UIColor(argb: tempPublicLeg.line.style.backgroundColor)
} else {
print("IndividualLeg")
var tempIndLeg = resultLegArray[selectedIndex][0].last as! IndividualLeg
cell.timeMiddleLabel.text = timeFormatHHMM.string(from: tempIndLeg.arrivalTime)
cell.timeMiddleLabel.textColor = UIColor.label
sideColor = UIColor.lightGray
}
} else {
//Not last cell (here is first and every other cell)
//Location cell
//Show Time
if arrayIndex == 0 {
//first cell
sideLineType = "start"
cell.timeTopLabel.isHidden = true
cell.timeMiddleLabel.isHidden = false
cell.timeBottomLabel.isHidden = true
if resultLegArray[selectedIndex][0][arrayIndex] is PublicLeg {
print("PublicLeg")
var tempPublicLeg = resultLegArray[selectedIndex][0][arrayIndex] as! PublicLeg
if tempPublicLeg.departureStop.predictedTime == nil {
cell.timeMiddleLabel.textColor = .label
cell.timeMiddleLabel.text = timeFormatHHMM.string(from: tempPublicLeg.departureStop.plannedTime)
} else if tempPublicLeg.departureStop.plannedTime == tempPublicLeg.departureStop.predictedTime {
cell.timeMiddleLabel.text = timeFormatHHMM.string(from: tempPublicLeg.departureStop.predictedTime!)
cell.timeMiddleLabel.textColor = UIColor.systemGreen
} else {
let timeDifference = tempPublicLeg.departureStop.plannedTime.distance(to: (tempPublicLeg.departureStop.predictedTime ?? tempPublicLeg.departureStop.plannedTime)!)
cell.timeMiddleLabel.text = timeFormatHHMM.string(from: tempPublicLeg.departureStop.predictedTime!)
cell.timeMiddleLabel.textColor = UIColor.systemRed
if timeDifference.stringFromTimeIntervalOnlyNumber().contains("-") == true {
cell.timeMiddleLabel.textColor = UIColor.systemBlue
}
}
sideColor = UIColor(argb: tempPublicLeg.line.style.backgroundColor)
} else {
print("IndividualLeg")
var tempIndLeg = resultLegArray[selectedIndex][0][arrayIndex] as! IndividualLeg
sideColor = UIColor.lightGray
cell.timeMiddleLabel.text = timeFormatHHMM.string(from: tempIndLeg.departureTime)
cell.timeMiddleLabel.textColor = UIColor.label
}
} else {//MARK: sideLineType Middle eg. every cell besiddes first and last
sideLineType = "middle"
cell.timeTopLabel.isHidden = false
cell.timeMiddleLabel.isHidden = true
cell.timeBottomLabel.isHidden = false
if resultLegArray[selectedIndex][0][arrayIndex] is PublicLeg {
print("PublicLeg")
var tempPublicLeg = resultLegArray[selectedIndex][0][arrayIndex] as! PublicLeg
if tempPublicLeg.departureStop.predictedTime == nil {
cell.timeBottomLabel.textColor = .label
cell.timeBottomLabel.text = timeFormatHHMM.string(from: tempPublicLeg.departureStop.plannedTime)
} else if tempPublicLeg.departureStop.plannedTime == tempPublicLeg.departureStop.predictedTime {
cell.timeBottomLabel.text = timeFormatHHMM.string(from: tempPublicLeg.departureStop.predictedTime!)
cell.timeBottomLabel.textColor = UIColor.systemGreen
} else {
let timeDifference = tempPublicLeg.departureStop.plannedTime.distance(to: tempPublicLeg.departureStop.predictedTime! )
cell.timeBottomLabel.text = timeFormatHHMM.string(from: tempPublicLeg.departureStop.predictedTime!)
cell.timeBottomLabel.textColor = UIColor.systemRed
if timeDifference.stringFromTimeIntervalOnlyNumber().contains("-") == true {
cell.timeBottomLabel.textColor = UIColor.systemBlue
}
}
sideBottomColor = UIColor(argb: tempPublicLeg.line.style.backgroundColor)
} else {
print("IndividualLeg")
var tempIndLeg = resultLegArray[selectedIndex][0][arrayIndex] as! IndividualLeg
sideBottomColor = UIColor.lightGray
cell.timeBottomLabel.text = timeFormatHHMM.string(from: tempIndLeg.departureTime)
cell.timeBottomLabel.textColor = UIColor.label
}
if resultLegArray[selectedIndex][0][arrayIndex-1] is PublicLeg { //Line before current
print("PublicLeg")
var tempPublicLeg = resultLegArray[selectedIndex][0][arrayIndex-1] as! PublicLeg
sideTopColor = UIColor(argb: tempPublicLeg.line.style.backgroundColor)
if tempPublicLeg.arrivalStop.predictedTime == nil {
cell.timeTopLabel.textColor = .label
cell.timeTopLabel.text = timeFormatHHMM.string(from: tempPublicLeg.arrivalStop.plannedTime)
} else if tempPublicLeg.arrivalStop.plannedTime == tempPublicLeg.arrivalStop.predictedTime {
cell.timeTopLabel.text = timeFormatHHMM.string(from: resultLegArray[selectedIndex][0][arrayIndex-1].arrivalTime)
cell.timeTopLabel.textColor = UIColor.systemGreen
} else {
let timeDifference = resultLegArray[selectedIndex][0][arrayIndex-1].plannedArrivalTime.distance(to: resultLegArray[selectedIndex][0][arrayIndex-1].arrivalTime )
cell.timeTopLabel.text = timeFormatHHMM.string(from: resultLegArray[selectedIndex][0][arrayIndex-1].arrivalTime)
cell.timeTopLabel.textColor = UIColor.systemRed
if timeDifference.stringFromTimeIntervalOnlyNumber().contains("-") == true {
cell.timeTopLabel.textColor = UIColor.systemBlue
}
}
} else {
print("IndividualLeg")
var tempIndLeg = resultLegArray[selectedIndex][0][arrayIndex-1] as! IndividualLeg
sideTopColor = UIColor.lightGray
cell.timeTopLabel.text = timeFormatHHMM.string(from: tempIndLeg.arrivalTime)
cell.timeTopLabel.textColor = UIColor.label
}
}
}
//Even index
} else {
//Info cell (Vehicle or Walk)
cell.timeTopLabel.isHidden = true
cell.timeMiddleLabel.isHidden = true
cell.timeBottomLabel.isHidden = true
sideLineType = "static"
cell.backgroundColor = UIColor.systemBackground
if resultLegArray[selectedIndex][0][arrayIndex] is PublicLeg {
//Fahrzeug
print("PublicLeg")
var tempPublicLeg = resultLegArray[selectedIndex][0][arrayIndex] as! PublicLeg
cell.lineNumberLabel.text = tempPublicLeg.line.label ?? ""
cell.destinationLabel.text = tempPublicLeg.destination?.name
if tempPublicLeg.line.style.backgroundColor2 == nil || tempPublicLeg.line.style.backgroundColor2 == 0 {
cell.lineNumberLabel.backgroundColorC = tempPublicLeg.line.style.backgroundColor
} else {
cell.lineNumberLabel.backgroundColorC = UInt32(UIColor.clear.hexa)
let backgroundLineHalfHalf = LineHalfTriangleView(frame: cell.lineNumberLabel.frame)
backgroundLineHalfHalf.topColor = tempPublicLeg.line.style.backgroundColor
backgroundLineHalfHalf.bottomColor = tempPublicLeg.line.style.backgroundColor2
backgroundLineHalfHalf.borderColor = tempPublicLeg.line.style.borderColor
cell.contentView.addSubview(backgroundLineHalfHalf)
cell.contentView.sendSubviewToBack(backgroundLineHalfHalf)
}
cell.lineNumberLabel.foregroundColor = tempPublicLeg.line.style.foregroundColor
cell.lineNumberLabel.roundCorners(corners: .allCorners, radius: 0)
//MARK: Info PublicLeg Time
if tempPublicLeg.departureTime == tempPublicLeg.plannedDepartureTime {
} else {
let timeDifference = tempPublicLeg.plannedDepartureTime.distance(to: tempPublicLeg.departureTime )
cell.timeTopLabel.text = timeDifference.stringFromTimeIntervalWithText()
cell.timeTopLabel.textColor = UIColor.systemRed
cell.timeTopLabel.isHidden = false
cell.timeTopLabel.text = "+ \(timeDifference.stringFromTimeIntervalOnlyNumber())"
if cell.timeTopLabel.text?.contains("-") == true {
cell.timeTopLabel.text = cell.timeTopLabel.text?.replacingOccurrences(of: "+ ", with: "")
cell.timeTopLabel.text = cell.timeTopLabel.text?.replacingOccurrences(of: "-", with: "- ")
cell.timeTopLabel.textColor = UIColor.systemBlue
}
}
if tempPublicLeg.arrivalTime == tempPublicLeg.plannedArrivalTime {
} else {
let timeDifference = tempPublicLeg.plannedArrivalTime.distance(to: tempPublicLeg.arrivalTime )
cell.timeBottomLabel.text = timeDifference.stringFromTimeIntervalWithText()
cell.timeBottomLabel.textColor = UIColor.systemRed
cell.timeBottomLabel.isHidden = false
cell.timeBottomLabel.text = "+ \(timeDifference.stringFromTimeIntervalOnlyNumber())"
if cell.timeBottomLabel.text?.contains("-") == true {
cell.timeBottomLabel.text = cell.timeBottomLabel.text?.replacingOccurrences(of: "+ ", with: "")
cell.timeBottomLabel.text = cell.timeBottomLabel.text?.replacingOccurrences(of: "-", with: "- ")
cell.timeBottomLabel.textColor = UIColor.systemBlue
}
}
if cell.timeTopLabel.text == cell.timeBottomLabel.text {
cell.timeTopLabel.isHidden = true
cell.timeBottomLabel.isHidden = true
cell.timeMiddleLabel.isHidden = false
cell.timeMiddleLabel.text = cell.timeTopLabel.text
cell.timeMiddleLabel.textColor = cell.timeTopLabel.textColor
}
sideColor = UIColor(argb: tempPublicLeg.line.style.backgroundColor)
cell.lineNumberLabel.shape = tempPublicLeg.line.style.shape
//Expandable Cell
let intermediateTableView = detailVerbindungIntermediateStopsTableView(frame: CGRect(x: 0, y: cell.frame.height, width: cell.frame.width, height: .zero))
intermediateTableView.translatesAutoresizingMaskIntoConstraints = false
intermediateTableView.register(detailVerbindungIntermediateStopTableViewCell.self, forCellReuseIdentifier: "detailVerbindungIntermediateStopTableViewCell")
intermediateTableView.dataSource = cell
intermediateTableView.delegate = cell
intermediateTableView.estimatedRowHeight = 20
intermediateTableView.rowHeight = 20
intermediateTableView.separatorInset.left = 96
cell.contentView.addSubview(intermediateTableView)
cell.intermediateStops = tempPublicLeg.intermediateStops
cell.sideColor = sideColor
let bottomConstraint = NSLayoutConstraint(item: intermediateTableView, attribute: .top, relatedBy: .equal, toItem: cell.destinationLabel, attribute: .bottom, multiplier: 1.0, constant: 0)
let leadingConstraint = NSLayoutConstraint(item: intermediateTableView, attribute: .leading, relatedBy: .equal, toItem: cell.contentView, attribute: .leading, multiplier: 1.0, constant: 0)
let trailingConstraint = NSLayoutConstraint(item: intermediateTableView, attribute: .trailing, relatedBy: .equal, toItem: cell.contentView, attribute: .trailing, multiplier: 1.0, constant: 0)
let heightConstraint = NSLayoutConstraint(item: intermediateTableView, attribute: .height, relatedBy: .greaterThanOrEqual, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 20)
cell.contentView.addConstraints([bottomConstraint, leadingConstraint, trailingConstraint, heightConstraint])
} else {
//Walk
print("IndividualLeg")
var tempIndLeg = resultLegArray[selectedIndex][0][arrayIndex] as! IndividualLeg
cell.destinationLabel.text = "Fußweg: \(tempIndLeg.departure.getDistanceText(CLLocation(latitude: CLLocationDegrees(tempIndLeg.arrival.coord?.lat ?? 0)/1000000, longitude: CLLocationDegrees(tempIndLeg.arrival.coord?.lon ?? 0)/1000000)))"
let config = UIImage.SymbolConfiguration(paletteColors: [.label, .lightGray])
let walkIconImgView = UIImageView(frame: CGRect(x: 96, y: 24, width: 42, height: 42))
walkIconImgView.contentMode = .scaleAspectFit
walkIconImgView.image = UIImage(systemName: "figure.walk.diamond")!.applyingSymbolConfiguration(config)
cell.addSubview(walkIconImgView)
walkIconImgView.isHidden = true
let imageAttachment = NSTextAttachment()
imageAttachment.image = UIImage(systemName: "figure.walk", withConfiguration: config)
let fullString = NSMutableAttributedString(string: "")
fullString.append(NSAttributedString(attachment: imageAttachment))
cell.lineNumberLabel.attributedText = fullString
sideColor = UIColor.lightGray
}
}
switch sideLineType {
case "middle": // ⎡ Comes from bottom to top
// Create the ⏐ UIView
let leftView = UIView()
leftView.frame = CGRect(x: 0, y: cell.sideLineView.frame.height / 2 + 7, width: 6, height: cell.sideLineView.frame.height / 2)
leftView.backgroundColor = sideBottomColor
// Create the ⎯ UIView
let rightView = UIView()
rightView.frame = CGRect(x: 0, y: cell.sideLineView.frame.height / 2 + 7, width: cell.sideLineView.frame.width, height: 6)
rightView.backgroundColor = sideBottomColor
// Add the subviews to the container view
cell.sideLineView.addSubview(leftView)
cell.sideLineView.addSubview(rightView)
// ⎣ Comes from top to bottom
// Create the ⏐ UIView
let topLeftView = UIView()
topLeftView.frame = CGRect(x: 0, y: 0, width: 6, height: cell.sideLineView.frame.height / 2 - 11)
topLeftView.backgroundColor = sideTopColor
// Create the ⎯ UIView
let topRightView = UIView()
topRightView.frame = CGRect(x: 0, y: cell.sideLineView.frame.height / 2 - 11, width: cell.sideLineView.frame.width, height: 6)
topRightView.backgroundColor = sideTopColor
// Add the subviews to the container view
cell.sideLineView.addSubview(topLeftView)
cell.sideLineView.addSubview(topRightView)
case "start": // ⎡
let sideLineMainView = UIView(frame: CGRect(x: 0, y: cell.sideLineView.frame.height / 2 - 3, width: 6, height: cell.sideLineView.frame.height))
sideLineMainView.backgroundColor = sideColor
cell.sideLineView.addSubview(sideLineMainView)
let sideLineSideView = UIView(frame: CGRect(x: 0, y: cell.sideLineView.frame.height / 2 - 3, width: cell.sideLineView.frame.width, height: 6))
sideLineSideView.backgroundColor = sideColor
cell.sideLineView.addSubview(sideLineSideView)
case "end": // ⎣
let sideLineMainView = UIView(frame: CGRect(x: 0, y: 0, width: 6, height: cell.sideLineView.frame.height / 2 + 3))
sideLineMainView.backgroundColor = sideColor
cell.sideLineView.addSubview(sideLineMainView)
let sideLineSideView = UIView(frame: CGRect(x: 0, y: cell.sideLineView.frame.height / 2 - 3, width: cell.sideLineView.frame.width, height: 6))
sideLineSideView.backgroundColor = sideColor
cell.sideLineView.addSubview(sideLineSideView)
case "static": // ⎥
let sideLineMainView = UIView(frame: CGRect(x: 0, y: 0, width: 6, height: cell.sideLineView.frame.height))
sideLineMainView.backgroundColor = sideColor
cell.sideLineView.addSubview(sideLineMainView)
default: break
}
}
return cell
}
This is my didSelectRowAt method:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row / 2 >= resultLegArray[selectedIndex][0].count {
return
}
if resultLegArray[selectedIndex][0][indexPath.row / 2] is PublicLeg && indexPath.row % 2 != 0 {
if expandedRowIndex == indexPath.row {
expandedRowIndex = -1
} else {
expandedRowIndex = indexPath.row
}
tableView.reloadRows(at: [indexPath], with: .automatic)
} else {
tableView.deselectRow(at: indexPath, animated: false)
}
}
And this my custom tableView Cell that is displayed inside the main cells:
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 20
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 20
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return intermediateStops.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "detailVerbindungIntermediateStopTableViewCell", for: indexPath) as! detailVerbindungIntermediateStopTableViewCell
cell.stopLabel.text = intermediateStops[indexPath.row].location.name
if let time = intermediateStops[indexPath.row].departure?.time {
cell.timeLabel.text = timeFormatHHMM.string(from: time)
} else {
cell.timeLabel.text = ""
}
let sideLineMainView = UIView(frame: CGRect(x: 0, y: 0, width: 6, height: 20))
sideLineMainView.backgroundColor = sideColor
cell.lineImageView.addSubview(sideLineMainView)
cell.rightLabel.isHidden = true
if intermediateStops[indexPath.row].departure?.predictedTime == nil {
//Keine Live
cell.timeLabel.textColor = UIColor.label
if let time = intermediateStops[indexPath.row].departure?.plannedTime {
cell.timeLabel.text = timeFormatHHMM.string(from: time)
} else {
cell.timeLabel.text = ""
} } else {
//Live
if intermediateStops[indexPath.row].departure?.predictedTime == intermediateStops[indexPath.row].departure?.plannedTime {
//Pünktlich
cell.timeLabel.textColor = UIColor.systemGreen
cell.timeLabel.text = timeFormatHHMM.string(from: intermediateStops[indexPath.row].departure!.plannedTime)
} else {
//Außerfahrplanmäßige Zeit
let timeDifference = intermediateStops[indexPath.row].departure?.predictedTime?.timeIntervalSince(intermediateStops[indexPath.row].departure!.plannedTime)
let delayAttString = NSMutableAttributedString()
var delayString = NSAttributedString()
var timeString = NSAttributedString()
let firstKlammer = NSAttributedString(string: "(", attributes: [NSAttributedString.Key.foregroundColor: UIColor.label])
let secondKlammer = NSAttributedString(string: ")", attributes: [NSAttributedString.Key.foregroundColor: UIColor.label])
if timeDifference!.stringFromTimeIntervalWithText().contains("-") {
delayString = NSAttributedString(string: timeDifference!.stringFromTimeIntervalOnlyNumber(), attributes: [NSAttributedString.Key.foregroundColor: UIColor.systemBlue])
timeString = NSAttributedString(string: timeFormatHHMM.string(from: (intermediateStops[indexPath.row].departure?.predictedTime)!), attributes: [NSAttributedString.Key.foregroundColor: UIColor.systemBlue])
cell.timeLabel.textColor = .systemBlue
} else {
delayString = NSAttributedString(string: "+\(timeDifference!.stringFromTimeIntervalOnlyNumber())", attributes: [NSAttributedString.Key.foregroundColor: UIColor.systemRed])
timeString = NSAttributedString(string: timeFormatHHMM.string(from: (intermediateStops[indexPath.row].departure?.predictedTime)!), attributes: [NSAttributedString.Key.foregroundColor: UIColor.systemRed])
cell.timeLabel.textColor = .systemRed
}
delayAttString.append(firstKlammer)
delayAttString.append(delayString)
delayAttString.append(secondKlammer)
cell.timeLabel.text = timeFormatHHMM.string(from: (intermediateStops[indexPath.row].departure?.predictedTime)!)
cell.rightLabel.isHidden = false
cell.rightLabel.attributedText = delayAttString
}
}
return cell
}
Sorry for that much code, I appreciate your help and hope I gave you the right information.
Thanks!
I have a collection view cell which loads images. On each cell I allow users to long press which pops up buttons with icons which can allow users to click on. Upon clicking on the buttons I show the type of icon they clicked on as a form of rating. My issue now is currently if I scroll down and comes up to the top the button on the image which I displayed after the user has clicked is no longer there. How do I keep the icons stacked to the image even if I scroll
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reUseMoviesCellID, for: indexPath) as! MoviesCollectionCell
cell.btnSmallGoodRate.id = self.movieObj[indexPath.row].id ?? ""
cell.btnSmallOkRate.id = self.movieObj[indexPath.row].id ?? ""
cell.btnSmallHateRate.id = self.movieObj[indexPath.row].id ?? ""
cell.btnSmallLoveRate.id = self.movieObj[indexPath.row].id ?? ""
cell.tapHandler = {
Commons.userGlobalRate += 1
self.lblRated.text = "\(Commons.userGlobalRate) rated"
self.ratedView.backgroundColor = .ratedGoldColour
if Commons.progressBarValue < 1 {
Commons.progressBarValue += 0.2
self.ratedTrackBarView.setProgress(Commons.progressBarValue, animated: true)
}
}
cell.configure(with: movieObj[indexPath.row])
let ids = ["id" : movieObj[indexPath.row].id!]
excludedDictionary.append(ids)
return cell
}
class MoviesCollectionCell: UICollectionViewCell {
var tapHandler: (()->())?
let movieImage: UIImageView = {
let image = UIImageView()
image.translatesAutoresizingMaskIntoConstraints = false
image.clipsToBounds = true
image.contentMode = .scaleAspectFill
image.layer.cornerRadius = 10
return image
}()
let movieOverlay: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .black.withAlphaComponent(0.3)
view.alpha = 0
return view
}()
let btnRate: UIImageView = {
let image = UIImageView()
image.translatesAutoresizingMaskIntoConstraints = false
image.clipsToBounds = true
image.contentMode = .scaleAspectFit
image.alpha = 0
return image
}()
let btnSmallGoodRate: ButtonRating = {
let btn = ButtonRating()
btn.translatesAutoresizingMaskIntoConstraints = false
btn.setImage(UIImage(named: "goodRate"), for: .normal)
btn.addTarget(self, action: #selector(goodItem(_:)), for: .touchUpInside)
btn.backgroundColor = .black.withAlphaComponent(0.4)
btn.layer.cornerRadius = 30
btn.alpha = 0
return btn
}()
let removeOverlay: UIButton = {
let btn = UIButton()
btn.translatesAutoresizingMaskIntoConstraints = false
btn.setImage(UIImage(systemName: "xmark"), for: .normal)
btn.tintColor = .black
btn.contentMode = .scaleAspectFit
btn.backgroundColor = .white.withAlphaComponent(0.7)
btn.layer.cornerRadius = 10
btn.contentEdgeInsets = UIEdgeInsets(top: 4, left: 4, bottom: 4, right: 4)
btn.addTarget(self, action: #selector(dismissOverlay), for: .touchUpInside)
btn.alpha = 0
return btn
}()
let btnSmallHateRate: ButtonRating = {
let btn = ButtonRating()
btn.translatesAutoresizingMaskIntoConstraints = false
btn.clipsToBounds = true
btn.contentMode = .scaleAspectFit
btn.setImage(UIImage(named: "HateIt"), for: .normal)
btn.alpha = 0
btn.addTarget(self, action: #selector(hateItem(_:)), for: .touchUpInside)
btn.backgroundColor = .black.withAlphaComponent(0.4)
btn.layer.cornerRadius = 30
return btn
}()
override init(frame: CGRect) {
super.init(frame: frame)
contentView.addSubview(movieImage)
movieImage.addSubview(btnRate)
movieImage.addSubview(movieOverlay)
contentView.addSubview(btnSmallGoodRate)
contentView.addSubview(btnSmallHateRate)
contentView.addSubview(removeOverlay)
let directFullPreviewer = UILongPressGestureRecognizer(target: self, action: #selector(directFullPreviewLongPressAction))
addGestureRecognizer(directFullPreviewer)
btnRate.tintColor = .white
btnRate.layer.shadowColor = UIColor.black.cgColor
btnRate.layer.shadowOffset = CGSize(width: 1.0, height: 2.0)
btnRate.layer.shadowRadius = 2
btnRate.layer.shadowOpacity = 0.8
btnRate.layer.masksToBounds = false
}
override func prepareForReuse() {
super.prepareForReuse()
movieImage.image = nil
btnRate.image = nil
}
func configure(with res: Responder){
movieImage.sd_setImage(with: URL(string: res.packShot?.thumbnail ?? ""), placeholderImage: UIImage(named: "ImagePlaceholder"))
}
#objc func directFullPreviewLongPressAction(g: UILongPressGestureRecognizer)
{
if g.state == UIGestureRecognizer.State.began
{
movieOverlay.alpha = 1
btnSmallGoodRate.alpha = 1
btnSmallHateRate.alpha = 1
removeOverlay.alpha = 1
btnHidden.alpha = 1
}
}
#objc func dismissOverlay(){
movieOverlay.alpha = 0
btnSmallHateRate.alpha = 0
btnSmallGoodRate.alpha = 0
removeOverlay.alpha = 0
btnHidden.alpha = 0
}
#objc func hateItem(_ sender: UIButton){
guard let gestureVariable = sender as? ButtonRating else{
return
}
let movieID = gestureVariable.id
print("Hate movie ID ", movieID)
btnSmallOkRate.alpha = 0
btnSmallHateRate.alpha = 0
btnSmallGoodRate.alpha = 0
btnSmallLoveRate.alpha = 0
removeOverlay.alpha = 0
btnRate.alpha = 1
btnRate.image = UIImage(named: "HateIt")
tapHandler?()
}
#objc func goodItem(_ sender: UIButton){
guard let gestureVariable = sender as? ButtonRating else{
return
}
let movieID = gestureVariable.id
print("Good movie ID ", movieID)
btnSmallOkRate.alpha = 0
btnSmallHateRate.alpha = 0
btnSmallGoodRate.alpha = 0
btnSmallLoveRate.alpha = 0
removeOverlay.alpha = 0
btnRate.alpha = 1
btnRate.image = UIImage(named: "goodRate")
tapHandler?()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Cell will dequeueReusableCell after it disapear from scrollview, so u should
set the bool value to reduction.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reUseMoviesCellID, for: indexPath) as! MoviesCollectionCell
cell.btnSmallGoodRate.id = self.movieObj[indexPath.row].id ?? ""
cell.btnSmallOkRate.id = self.movieObj[indexPath.row].id ?? ""
cell.btnSmallHateRate.id = self.movieObj[indexPath.row].id ?? ""
cell.btnSmallLoveRate.id = self.movieObj[indexPath.row].id ?? ""
cell.tapHandler = {
cell.isTap = true
Commons.userGlobalRate += 1
self.lblRated.text = "\(Commons.userGlobalRate) rated"
self.ratedView.backgroundColor = .ratedGoldColour
if Commons.progressBarValue < 1 {
Commons.progressBarValue += 0.2
self.ratedTrackBarView.setProgress(Commons.progressBarValue, animated: true)
}
}
if cell.isTap{
self.lblRated.text = "\(Commons.userGlobalRate) rated"
self.ratedView.backgroundColor = .ratedGoldColour
if Commons.progressBarValue < 1 {
Commons.progressBarValue += 0.2
self.ratedTrackBarView.setProgress(Commons.progressBarValue, animated: true)
}
}
cell.configure(with: movieObj[indexPath.row])
let ids = ["id" : movieObj[indexPath.row].id!]
excludedDictionary.append(ids)
return cell
}
class MoviesCollectionCell: UICollectionViewCell {
var tapHandler: (()->())?
var isTap = false
}
You need to maintain press action inside "movieObj". Because the cell is always reusable.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reUseMoviesCellID, for: indexPath) as! MoviesCollectionCell
cell.btnSmallGoodRate.id = self.movieObj[indexPath.row].id ?? ""
cell.btnSmallOkRate.id = self.movieObj[indexPath.row].id ?? ""
cell.btnSmallHateRate.id = self.movieObj[indexPath.row].id ?? ""
cell.btnSmallLoveRate.id = self.movieObj[indexPath.row].id ?? ""
cell.tapHandler = {
movieObj[indexPath.row].isTapped = true
Commons.userGlobalRate += 1
self.lblRated.text = "\(Commons.userGlobalRate) rated"
self.ratedView.backgroundColor = .ratedGoldColour
if Commons.progressBarValue < 1 {
Commons.progressBarValue += 0.2
self.ratedTrackBarView.setProgress(Commons.progressBarValue, animated: true)
}
}
if movieObj[indexPath.row].isTapped {
self.lblRated.text = "\(Commons.userGlobalRate) rated"
self.ratedView.backgroundColor = .ratedGoldColour
if Commons.progressBarValue < 1 {
Commons.progressBarValue += 0.2
self.ratedTrackBarView.setProgress(Commons.progressBarValue, animated: true)
}
}
}
I have a strange problem with tableView cell.
when I scroll tableView and cell disappear and back again to the cell I understand that tableView add similar cell exactly on cell.
for example look at the picture . 3 exact text add on each other.
cellForRowAtIndexPath function :
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
if indexPath.row == 0 {
let reviewNumber = UILabel()
if (self.book.review_count == 0) {
reviewNumber.text = "\(self.lang.book["no_review"]!)"
}
if (self.book.review_count > 0) {
reviewNumber.text = "\(self.book.review_count!) \(self.lang.general["review"]!)"
}
reviewNumber.textAlignment = .Right
reviewNumber.font = UIFont(name: "Vazir", size: 14)
reviewNumber.numberOfLines = 0
reviewNumber.translatesAutoresizingMaskIntoConstraints = false
reviewNumber.textColor = UIColor.grayColor()
cell.contentView.addSubview(reviewNumber)
let voteIcon = UIImageView()
voteIcon.image = UIImage(named: "vote-icn")
voteIcon.translatesAutoresizingMaskIntoConstraints = false
cell.contentView.addSubview(voteIcon)
cell.contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-[v0(24)]-|",options: [],metrics: nil,views: ["v0" : voteIcon]))
let reviewIcon = UIImageView()
reviewIcon.image = UIImage(named: "review-icn")
reviewIcon.translatesAutoresizingMaskIntoConstraints = false
cell.contentView.addSubview(reviewIcon)
cell.contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-[v0(24)]-|",options: [],metrics: nil,views: ["v0" : reviewIcon]))
let voteNumber = UILabel()
voteNumber.text = " ۴.۵ از ۱۶۵۴رأی"
voteNumber.textAlignment = .Left
voteNumber.font = UIFont(name: "Vazir", size: 14)
voteNumber.numberOfLines = 0
voteNumber.translatesAutoresizingMaskIntoConstraints = false
voteNumber.textColor = UIColor.grayColor()
cell.contentView.addSubview(voteNumber)
cell.contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-3-[v0]-3-|",options: [],metrics: nil,views: ["v0" : reviewNumber]))
cell.contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-3-[v0]-3-|",options: [],metrics: nil,views: ["v0" : voteNumber]))
cell.contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-35-[v0]-8-[v1(25)]",options: [],metrics: nil,views: ["v0" : voteNumber, "v1" : voteIcon, "v2" : reviewNumber, "v3" : reviewIcon]))
cell.contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:[v2]-8-[v3(25)]-35-|",options: [],metrics: nil,views: ["v0" : voteNumber, "v1" : voteIcon, "v2" : reviewNumber, "v3" : reviewIcon]))
}
if indexPath.row == 1 {
let userBookStatusButtn = UIButton(type: .Custom)
userBookStatusButtn.setTitle("خواهم خواند", forState: .Normal)
userBookStatusButtn.alpha = 0.2
userBookStatusButtn.titleLabel?.font = UIFont(name: "Vazir", size: 14)
userBookStatusButtn.setTitleColor(UIColor.whiteColor(), forState: .Normal)
// userBookStatusButtn.setImage(UIImage(named: "vote-icn"), forState: .Normal)
userBookStatusButtn.translatesAutoresizingMaskIntoConstraints = false
userBookStatusButtn.backgroundColor = UIColor(red:0.0/256.0 ,green:150.0/256.0, blue:136.0/256.0 ,alpha:1 )
cell.contentView.addSubview(userBookStatusButtn)
cell.contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-20-[v0(48)]-20-|",options: [],metrics: nil,views: ["v0" : userBookStatusButtn]))
cell.contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-35-[v0]-35-|",options: [],metrics: nil,views: ["v0" : userBookStatusButtn]))
}
if indexPath.row == 2 {
let topBorder = UIView()
topBorder.translatesAutoresizingMaskIntoConstraints = false
topBorder.backgroundColor = UIColor(white: 0.5, alpha: 0.5)
cell.contentView.addSubview(topBorder)
let bottomBorder = UIView()
bottomBorder.translatesAutoresizingMaskIntoConstraints = false
bottomBorder.backgroundColor = UIColor(white: 0.5, alpha: 0.5)
cell.contentView.addSubview(bottomBorder)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 5
paragraphStyle.baseWritingDirection = .RightToLeft
guard let descriptionStr = self.book.description else {return cell}
let attrString = NSMutableAttributedString(string: descriptionStr)
attrString.addAttribute(NSParagraphStyleAttributeName, value:paragraphStyle, range:NSMakeRange(0, attrString.length))
let description = UILabel()
description.attributedText = attrString
description.textAlignment = .Justified
description.font = UIFont(name: "Vazir", size: 14)
description.numberOfLines = 0
description.translatesAutoresizingMaskIntoConstraints = false
description.lineBreakMode = NSLineBreakMode.ByWordWrapping
cell.contentView.addSubview(description)
let title = UILabel()
title.text = "\(self.lang.book["summery"]!)"
title.alpha = 0.2
title.textAlignment = .Center
title.font = UIFont(name: "Vazir-Bold", size: 16)
title.translatesAutoresizingMaskIntoConstraints = false
cell.contentView.addSubview(title)
cell.contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-[v0]-|",options: [.AlignAllCenterX],metrics: nil,views: ["v0" : title]))
cell.contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-20-[v0]-20-|",options: [],metrics: nil,views: ["v0" : description]))
cell.contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-8-[v1]-44-[v0]",options: [],metrics: nil,views: ["v0" : description,"v1" : title ]))
cell.contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:[v0]-8-|",options: [],metrics: nil,views: ["v0" : description,"v1" : title ]))
}
cell.textLabel?.text = nil
return cell
}
I get data from son file with Alamofire and reloadData :
func tableRefresh()
{
dispatch_async(dispatch_get_main_queue(), {
self.bookDetailTableView.reloadData()
})
}
what's my problem?
thanks guys.
You made a classical error when using iOS cells.
(I am a teacher, so I see this kind of error frequently... don't worry..)
some Considerations:
1) NEVER add a label to a cell. Doing so, very time a cell is reused, previous label stays here, and a new label is added
2) as label are transparent, you will see all text overlapped..
3) You are leaking memory, as no one will detach/ release labels.
so the way can be:
A)Simple for simple case
use TAGS, as Apple did on old days of cells..
(code i
make some defines:
let TEXT_TAG = 2000
add label if not present, if present get it vi TAG:
let cell = tableView.dequeueReusableCell(withIdentifier: REUSE, for: indexPath )
let text = "my text..."
if let label = cell.viewWithTag(TEXT_TAG) as? UILabel{
label.text = text
}else{
let frame = CGRect(x: 100, y: 20, width: 50, height: 50)
let label = UILabel(frame: frame)
label.text = text
cell.addSubview(label)
}
B) make a custom cell...
class CustomViewCell: UITableViewCell {
var label: UILabel?
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
let frame = CGRect(x: 100, y: 20, width: 50, height: 50)
let label = UILabel(frame: frame)
self.addSubview(label)
}
in controller simply:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: REUSE,
for: indexPath ) as! CustomViewCell
cell.label = "my text"
I get your problem,you get the cell from tableView reuseable pool.The first problem,if you want change UITableViewCell View,you need to creat a son class of it.I get a function to fix it.
I use Stackoverflow first time,I don't know where can I put my code,so I write it under this sentence.
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
for let item in cell.contentView.subviews {
item.removeFromSuperView();
}
And then using your code,it should help you.
I am trying to add UILabels in the subView of my Collection Cell.
But when I scroll to the other cell and come back all the UIlabels appear on both cells and some are written under the other..
I tried with collectionView.cellForItemAtIndexPath(indexPath) as? CollectionViewCell , but when I used it none UIlabel was displayed ( I tried with breaking points, it doesn't go after the if statement)
How can I fix it??
Thanks!!!
class CollectionView: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
var collection = [PFObject]()
#IBOutlet weak var collectionView: UICollectionView!
let sidePadding:CGFloat = 10
var checkLocation: Bool = false
override func viewDidLoad()
{
super.viewDidLoad();
self.collectionView!.delegate = self
self.collectionView!.dataSource = self
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.collection.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("CollectionCell", forIndexPath: indexPath) as! CollectionViewCell
cell.layer.borderColor = UIColor.lightGrayColor().CGColor
cell.layer.borderWidth = 0.5
cell.layer.cornerRadius = 3
let collectionViewWidth = self.collectionView.bounds.size.width - self.sidePadding * 2
cell.frame.size.width = collectionViewWidth
let collectionViewHeight = self.collectionView.bounds.size.height/4.5
cell.frame.size.height = collectionViewHeight
// Display the country name
if let value = self.collection[indexPath.row]["Name"] as? String {
cell.cellTitle.text = String(Int(indexPath.row)) + "." + value
}
let width = (cell.bounds.width - 94 - 4*3 - 60 - 20)/4
let cellheight = CGFloat(6)
let cellheight1 = CGFloat(6 + 12 + 2)
var array = [String]()
if let MWl = collection[indexPath.row]["MW"] as? Int
{
if MWl == 1 {
array.append("M")
} else if MWl == 2 {
array.append("M")
array.append("W")
}
}
if let JAl = collection[indexPath.row]["JA"] as? Int
{
if JAl == 1 {
array.append("Jy")
} else if JAl == 2 {
array.append("Jy")
array.append("Ac")
}
}
if let HK = collection[indexPath.row]["HK"] as? Int
{
if HK == 1 {
array.append("HB")
} else if HK == 2 {
array.append("HB")
array.append("Ks")
}
}
if let SSl = collection[indexPath.row]["SSl"] as? Int
{
if SSl == 1 {
array.append("AB")
} else if SSl == 2 {
array.append("AB")
array.append("CD")
}
//I tried here too
// if let myCell = collectionView.cellForItemAtIndexPath(indexPath) as? CollectionViewCell
if array.count <= 4 {
for i in 0..<array.count {
let taille = CGFloat(i)
var si = CGFloat((1+i)*3 + 94 + 30)
let label = UILabel() as UILabel
label.frame = CGRectMake((si + width*taille), cellheight, width, 12)
label.textColor = UIColor(red: 0/255, green: 125/255, blue: 255/255, alpha: 1.0)
label.backgroundColor = UIColor.clearColor()
label.layer.borderWidth = 0.7
label.layer.borderColor = UIColor.lightGrayColor().CGColor
label.font = UIFont(name: "Futura-Medium", size: 9)
label.textAlignment = NSTextAlignment.Center
label.numberOfLines = 1
label.text = array[i]
label.layer.masksToBounds = true
label.layer.cornerRadius = 3.5
if let myCell = collectionView.cellForItemAtIndexPath(indexPath) as? CollectionViewCell {
myCell.contentView.addSubview(label)
}
}
} else {
for i in 0...3 {
let taille = CGFloat(i)
var si = CGFloat((1+i)*3 + 94 + 30)
let label = UILabel() as UILabel
label.frame = CGRectMake((si + width*taille), cellheight, width, 12)
label.textColor = UIColor(red: 0/255, green: 125/255, blue: 255/255, alpha: 1.0)
label.backgroundColor = UIColor.clearColor()
label.layer.borderWidth = 0.7
label.layer.borderColor = UIColor.lightGrayColor().CGColor
label.font = UIFont(name: "Futura-Medium", size: 9)
label.textAlignment = NSTextAlignment.Center
label.numberOfLines = 1
label.text = array[i]
label.layer.masksToBounds = true
label.layer.cornerRadius = 3.5
if let myCell = collectionView.cellForItemAtIndexPath(indexPath) as? CollectionViewCell {
myCell.contentView.addSubview(label)
}
}
var j = 0 as Int
for i in 4..<array.count {
let taille = CGFloat(j)
let si = CGFloat((1+j)*3 + 94 + 30)
let label = UILabel() as UILabel
label.frame = CGRectMake((si + width*taille), cellheight1, width, 12)
label.textColor = UIColor(red: 0/255, green: 125/255, blue: 255/255, alpha: 1.0)
label.backgroundColor = UIColor.clearColor()
label.layer.borderWidth = 0.7
label.layer.borderColor = UIColor.lightGrayColor().CGColor
label.font = UIFont(name: "Futura-Medium", size: 9)
label.textAlignment = NSTextAlignment.Center
label.numberOfLines = 1
label.text = array[i]
label.layer.masksToBounds = true
label.layer.cornerRadius = 3.5
if let myCell = collectionView.cellForItemAtIndexPath(indexPath) as? CollectionViewCell {
myCell.contentView.addSubview(label)
}
j = j + 1
}
}
return cell
}
}
EDIT
I tried to create the UILabel programmatically. But in that way I used the elements designed with the StoryBoard and the elements created programmatically. And actually I can't because of this :
collectionView!.registerClass(RDCell.self, forCellWithReuseIdentifier: "Cell")
I create all the content of the cell programmatically ( the collectionView is created with the storyboard) and it works perfectly.
The cell is being reused, therefore you are always adding new labels each time cellForItemAtIndexPath is called. Just tag your labels like label.tag = 1 and when you dequeue the cell remove every subview with this tag, like
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("CollectionCell", forIndexPath: indexPath) as! CollectionViewCell
for view in cell.subviews {
if view.tag == 1 {
view.removeFromSuperview()
}
}
You will be always recreating the labels though, which is bad design. I suggest designing those labels on storyboard or if you insist on doing it in code keep optional references to the label in the cell to not recreate them each time cellForItemAtIndexPath is called.
not recommended but you can do is,
Add tag to each label like 1000 or something and find sub views of cell if any of subview tag matches with label tag remove that view
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("CollectionCell", forIndexPath: indexPath) as! CollectionViewCell
for let labelIs in cell.subviews
{
if labelIs.tag == 1000
{
labelIs.removeFromSuperview()
}
}
//some whare
var label = UILabel()
label.tag = 1000
return cell
}
i have problem in code but I don't understand where ?
is coming after slid table view to down !
like this image : http://s18.postimg.org/xgszi1l21/problem.png
d func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
// MARK: إنشاء ليبل عنوان القسم
let lblSectionName:UILabel = UILabel(frame: CGRect(x: 60, y: 7, width: self.view.frame.width - 70, height: 10))
lblSectionName.text = arraySectionName[indexPath.row] as? String
lblSectionName.textAlignment = NSTextAlignment.Right
lblSectionName.font = UIFont.systemFontOfSize(18)
lblSectionName.textColor = UIColor(netHex: 0x1484c4)
// lblSectionName.backgroundColor = UIColor.redColor()
// MARK: إنشاء ليبل وصف القسم
let lblSectionDescription:UILabel = UILabel(frame: CGRect(x: 65, y: 15, width: self.view.frame.width - 70, height: 45))
lblSectionDescription.numberOfLines = 2
lblSectionDescription.text = arraySectionDescription[indexPath.row] as? String
lblSectionDescription.textAlignment = NSTextAlignment.Right
lblSectionDescription.font = UIFont.systemFontOfSize(14)
lblSectionDescription.textColor = UIColor(netHex: 0x757575)
// MARK:\إنشاء صورة الأقسام
let imageName:NSString = arraySectionPathImage[indexPath.row] as NSString
let imageURL = NSURL(string: imageName)
let imageData = NSData(contentsOfURL: imageURL!)
let image = UIImage(data: imageData!)
let imageView = UIImageView(image: image!)
imageView.frame = CGRect(x: 4, y: 7.5, width:60, height: 60)
// Mark: لعمل الصورة بشكل دائري
// imageView.layer.cornerRadius = imageView.frame.size.width / 2 //MARK: لعمل الصوره بشكل دائري
imageView.layer.cornerRadius = 10.0 //MARK: لعمل منحنيات بالصوره
imageView.layer.borderColor = UIColor(netHex: 0xb5b5b5).CGColor
imageView.layer.backgroundColor = UIColor(netHex: 0x4183D7).CGColor
imageView.layer.borderWidth = 1.5
imageView.clipsToBounds = true
//
// cell.textLabel?.text = arraySectionName[indexPath.row] as? String
// MARK: تغيير لون خلفية View
view.backgroundColor = UIColor(netHex: 0xfafafa)
// MARK: لتغيير لون خلفية Cell
if((count%2) == 0)
{
cell.backgroundColor = UIColor(netHex: 0xf0f0f0)
}else
{
cell.backgroundColor = UIColor(netHex: 0xfafafa)
}
count++
// MARK: وضع المحتوى في Cell
cell.contentView.addSubview(lblSectionName)
cell.contentView.addSubview(lblSectionDescription)
cell.contentView.addSubview(imageView)
return cell
}