Whenever I scroll in the table view, the cell label's text disappears
which means the tableview data disappears. I tried changing the switch statement to if statement and it still doesn't work. Is my function to change the date format the reason?
Here is my code:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "requestsCell", for: indexPath) as! RequestsTableViewCell
let requesten = requestsList[indexPath.row]
switch requesten.type {
case "FLT" :
cell.requestType.text = "Flight"
let reqDateTimeDate = stringToDate(strdate: requesten.reqDate!)
cell.requestDate.text = "\(dateFormatterPrint.string(from: reqDateTimeDate))"
cell.fromDate.isHidden = true
cell.toDate.isHidden = true
case "DOF" :
cell.requestType.text = "Day Off"
let reqDateTimeDate = stringToDate(strdate: requesten.reqDate!)
cell.requestDate.text = "\(dateFormatterPrint.string(from: reqDateTimeDate))"
cell.fromDate.isHidden = true
cell.toDate.isHidden = true
case "VAC" :
cell.requestType.text = "Vacation"
let reqDateFrom = stringToDate(strdate: requesten.dateFrom!)
let reqDateTo = stringToDate(strdate: requesten.dateTo!)
cell.requestDate.isHidden = true
cell.toDate.text = "To: \(dateFormatterPrint.string(from: reqDateTo))"
cell.fromDate.text = "From: \(dateFormatterPrint.string(from: reqDateFrom))"
default:
cell.requestType.text = ""
}
return cell
}
You should set up your code better such that each and every case statement changes the same properties. Or you need to override the prepareForReuse method so that each time the cell is reset to a common state.
Looking at your code - every case statement should assign these properties:
requestType.text
requestDate.text
fromDate.isHidden
fromDate.text
toDate.isHidden
toDate.text
Related
I am facing problem in UITableView. I want change the label color on some condition. But it does not change on first reload. But when I start scrolling the new reusable cell change the text color.
Here is my code
I tried setNeedDesplay() and layoutIfNeeded() but not working either.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! WalletHistoryCell
let item = array[indexPath.row]
let amountDouble = Float(item.amount ?? "0.0")
cell.labelAmount.text = String.init(format: Constants.AMOUNT_PLACEHOLDER, amountDouble!)
cell.labelDateTime.text = item.dateTime ?? ""
if !(item.details?.isEmpty)!{
cell.labelReason.text = String.init(format: Constants.REASON_PLACEHOLDER, item.details!)
}
if item.debit!{
cell.labelName.text = item.toName ?? ""
cell.labelTo.text = item.toNum ?? ""
cell.labelAmount.textColor = UIColor.appDiscountColor
}else{
cell.labelName.text = item.fromName ?? ""
cell.labelTo.text = item.phoneNumber ?? ""
cell.labelAmount.textColor = UIColor.appHopOrbitColor
}
return cell
}
By default it must work correctly. I.e. the problem not in TableView or TableViewCell. The only reason I can suppose is that tableView.reloadData() calls earlier than array updates. You can recheck this by printing item in cellForRowAt method.
the text must be red when the variable beats == "true"
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! InstallmentTableViewCell
if self.switchInstallmentToPay == true {
if let installment = PaymentManager.paymentPlan?.unpaidInstallments![indexPath.row] {
if let id = installment.id, let paymentDue = installment.paymentDue, let description = installment.numberDescription, let method = installment.paymentMethodDescription, let expectedPayment = installment.expectedPayment, let actualPayment = installment.actualPayment, let payable = installment.payable, let late = installment.late {
cell.load(id: id, paymentDue: paymentDue, description: description, method: method, expectedPayment: expectedPayment, actualPayment: actualPayment, payable: payable, late: late)
if installment.payable! {
cell.accessoryType = .checkmark
cell.tintColor = UIColor.lighterGray
cell.isUserInteractionEnabled = true
if installment.late! {
cell.lbDescription.textColor = UIColor.danger // not working
}
}else{
cell.accessoryType = .none
//cell.tintColor = UIColor.lightGray
cell.isUserInteractionEnabled = false
}
}
}
}else{
if let installment = PaymentManager.paymentPlan?.paidInstallments![indexPath.row] {
if let id = installment.id, let paymentDue = installment.paymentDue, let description = installment.numberDescription, let method = installment.paymentMethodDescription, let expectedPayment = installment.expectedPayment, let actualPayment = installment.actualPayment, let payable = installment.payable, let late = installment.late {
cell.load(id: id, paymentDue: paymentDue, description: description, method: method, expectedPayment: expectedPayment, actualPayment: actualPayment, payable: payable, late: late)
cell.accessoryType = .none
cell.isUserInteractionEnabled = false
cell.lbDescription.textColor = UIColor.black // not working
cell.tintColor = UIColor.lighterGray
}
}
}
return cell
}
This code is difficult to read, and there's a lot of redundancy. If you're using a storyboard, I suggest making separate dynamic cells for the paid and unpaid installments. Both cells' class type can stay InstallmentTableViewCell, as you're just duplicating the cells' views, not their logic. The various elements' colors & styles can be set right in the storyboard's cell prototype, and then your tableView(_:cellForRowAt:indexPath) can be simplified to just
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellID = switchInstallmentToPay ? "unpaidCell" : "paidCell"
let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath) as! InstallmentTableViewCell
cell.load(...)
return cell
}
I would also recommend changing cell.load() to take an installment argument and setting the cells' properties there instead of cluttering the caller with multiple if lets.
I have the following problem.
example
If a cell has no content, I want to hide the cell. The logic as you can see allows, that constantly 5 cells get returned:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if(section == 0){
return 1
}
return 5
}
Here is the logic of the actual table view:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch indexPath.section{
case 0:
let cell = tableView.dequeueReusableCell(withIdentifier: "CampusGoogleMapsTableViewCell", for: indexPath) as! CampusGoogleMapsTableViewCell
if let building = self.selectedPOIOffice.room?.building{
cell.setMarkerForSelectedBuilding(building)
}
return cell
case 1:
let cell = tableView.dequeueReusableCell(withIdentifier: "CampusTableViewCell", for: indexPath) as! CampusTableViewCell
let iconLabel: UILabel = cell.iconLabel
let titleLabel: UILabel = cell.titleLabel
iconLabel.font = UIFont.fontAwesome(ofSize: 25, style: .solid)
switch indexPath.row{
case 0:
//name
titleLabel.text = selectedPOIOffice.name
titleLabel.textColor = UIColor.black
titleLabel.alpha = 0.8
iconLabel.text = FontAwesomeIcons.University.getIcon()
case 1:
//Phone
titleLabel.text = selectedPOIOffice.phone
titleLabel.textColor = HsKAmpusColors.Red
iconLabel.text = FontAwesomeIcons.Phone.getIcon()
case 2:
//email
titleLabel.text = selectedPOIOffice.email
titleLabel.textColor = HsKAmpusColors.Red
iconLabel.text = FontAwesomeIcons.Mail.getIcon()
case 3:
//Opening Hours
if(titleLabel.text == nil){ break}
titleLabel.text = selectedPOIOffice.openingHours
titleLabel.textColor = UIColor.black
titleLabel.alpha = 0.8
iconLabel.text = FontAwesomeIcons.Clock.getIcon()
case 4:
//Location
titleLabel.text = selectedPOIOffice.room?.roomAndBuildingString ?? ""
titleLabel.textColor = UIColor.black
titleLabel.alpha = 0.8
iconLabel.text = FontAwesomeIcons.PositionMarker.getIcon()
default:
break
}
return cell
default:
return UITableViewCell()
}
}
I think I could solve it with a simple for-statement to check if every cell has any content. Can you help me please with the application?
You are going about this all wrong. cellForRowAt is not the place to attempt to hide a cell. By the time it is called, the cell is going to be shown.
Do one of two things:
Update your data model used by your data source methods to only include the data you want to display. Or...
Implement heightForRowAt to return 0 for rows you don't wish to see.
"If a cell has no content, I want to hide the cell."
That sentence shows a basic misunderstanding of how table views and collection views work. Table views display tabular data from a data model. If you have empty entries in your model, remove them from the model before giving it to the table view.
I am new to swift . i am doing my project programatically and I load data from api to the tableView and tableView like ios setting page ..
now i need all rows information when click "Add to cart" button. How can i do it?
here is my code sample :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch indexPath.section {
case 0:
let cell = tableView.dequeueReusableCell(withIdentifier: cartHeaderCell, for: indexPath) as! CartHeaderCell
cell.configureCell(indexPath.item)
return cell
case 1:
let obj = data?[indexPath.row]
var cell = UITableViewCell()
switch obj {
case is Addon:
cell = tableView.dequeueReusableCell(withIdentifier: addonCell, for: indexPath) as! AddonCell
let switchView = UISwitch(frame: .zero)
switchView.setOn(false, animated: true)
cell.accessoryView = switchView
guard let addon = obj as? Addon else {
return cell
}
cell.textLabel?.text = "\(addon.name) + €\(addon.price)"
case is AddonGroup:
cell = tableView.dequeueReusableCell(withIdentifier: addonGroupCell, for: indexPath) as! AddonGroupCell
cell.accessoryType = UITableViewCellAccessoryType.disclosureIndicator
guard let addonGroup = obj as? AddonGroup else {
return cell
}
if let addons = addonGroup.addonList {
cell.detailTextLabel?.text = ""
var selectedAddons = ""
for _addon in addons
{
if _addon.isSelect == true {
selectedAddons = selectedAddons + "\(_addon.name)"
}
}
cell.detailTextLabel?.text = selectedAddons
}
cell.textLabel?.text = addonGroup.name
...........................................
As Fahim was mentioning, you need to set up a data model that records that status of each cell before / during / after the user interaction with each cell. So when the cell goes off screen and then comes back on, it will be presented with the correct state of the model.
Secondly, for the UISwitchViews, you should be instantiating and adding those to the contentView within each cell in order to keep the cellForRow function clean and problem free. The reason leads me into my next point: how to record the status of each UISwitchView after the user has interacted with a UISwitchView. You are going to want to create a protocol and add a delegate within the UICollectionViewCell(that inherits class and the delegate should be a weak var), in order to update the model whenever the UISwitch is tapped.
If you have any more questions i can do my best to help!
I want to hide the label in a cell that was tapped and instead show an image. But I want to do this only if a cell with a certain index has already been set to the imageView.
What is the best way to address the cells and store if they are set to imageView or not? How do I use the prepareForReuse method?
This is the way I do it until now, but as the cells are reused. The image is shown in other cells at scrolling.
override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
println("user tapped on door number \(indexPath.row)")
let cell = collectionView.cellForItemAtIndexPath(indexPath) as! MyCollectionViewCell
if (cell.myLabel.text == "1") {
one = true
if(seven = true) {
if (cell.myLabel.hidden) {
cell.myLabel.hidden = false
cell.MyImageView.image = nil
}
else {
cell.myLabel.hidden = true
cell.MyImageView.image = UIImage(named:"1")!
}
}
}
You didn't say if your collection view has exactly 7 cells or if it can have "N" (e.g. 100) cells in the collection, so if this were my problem and I had to solve it, I would make the state of your "seven" cell a property of the class (e.g. "var sevenState : Bool") and then I could display the button or image of other cells depending on what sevenState is.
In my app I have to configure a UICollectionReusableView based on the index path, if the indexPath has a particular value then I send an array which is used to set labels and images.
I use a function in the custom UICollectionReusableView, if I call it with an array it populates the labels and images and if I call it with nil it resets these.
func collectionView(collectionView: UICollectionView!, viewForSupplementaryElementOfKind kind: String!, atIndexPath indexPath: NSIndexPath!) -> UICollectionReusableView! {
.... [logic around selecting index path based on data returned]
....
if filteredEvents != nil{
reusableView.populateCalendarDayDates(sortedEvents)
}else{
reusableView.populateCalendarDayDates(nil)
}
In the function in the custom UICollectionReusableView I reset labels back to default values before possibly updating them :
func populateCalendarDayDates(arrayEvents: NSArray?){
let firstDayTag = tagStartDay()
var dayDate = 1
for var y = 1; y < 43; y++ {
let label = self.viewWithTag(y) as! BGSCalendarMonthLabel
label.delegate = callingCVC
label.backgroundColor = UIColor.clearColor()
label.textColor = UIColor.whiteColor()
label.text = ""
You can get the same effect, and it is probably a bit more readable, by moving this code to prepareForReuse in the custom UICollectionReusableView :
override func prepareForReuse() {
super.prepareForReuse()
for var y = 1; y < 43; y++ {
let label = self.viewWithTag(y) as! BGSCalendarMonthLabel
label.backgroundColor = UIColor.clearColor()
label.textColor = UIColor.whiteColor()
label.text = ""
}
}
Hope that helps.