I am having a strange issue with displaying a switch in a dynamic tableview: one of the UISwitch instances is aligned to the left. As soon as it is switched, it goes back to normal...for a while.
Reproduction of the issue
I can reproduce the issue on a physical devices and simulators for all types of devices. The row where the problem occurs depends on the screen size of the device: it seems to be the first row that is invisible at the start. On small devices row 8, on larger iPhones row 10 or 11. When I scroll, the same row is affected.
Screen shot:
My code:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return woordeninlijst.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let CellIdentifier = "Cell"
let cell = tableView.dequeueReusableCell(withIdentifier: CellIdentifier, for: indexPath) as! WoordTableViewCell
cell.woordLabel.text = woordeninlijst[indexPath.row].naam
cell.hulpWoordLabel.text = woordeninlijst[indexPath.row].hulpWoord
var scoreImage = [0: #imageLiteral(resourceName: "score grijs"), 1: #imageLiteral(resourceName: "score oranje"), 2: #imageLiteral(resourceName: "score geel"), 3: #imageLiteral(resourceName: "score groen")]
cell.score1.image = scoreImage[Int(woordeninlijst[indexPath.row].score1)]
cell.score2.image = scoreImage[Int(woordeninlijst[indexPath.row].score2)]
cell.score3.image = scoreImage[Int(woordeninlijst[indexPath.row].score3)]
cell.score4.image = scoreImage[Int(woordeninlijst[indexPath.row].score4)]
cell.score5.image = scoreImage[Int(woordeninlijst[indexPath.row].score5)]
let activeSwitch = UISwitch()
cell.accessoryView = activeSwitch
activeSwitch.addTarget(self, action: #selector(WoordTableViewController.switchChanged(sender:)), for: UIControlEvents.valueChanged)
activeSwitch.tag = indexPath.row
activeSwitch.isOn = woordeninlijst[indexPath.row].isActive
return cell
}
#objc func switchChanged(sender: UISwitch!) {
print("Switch value is \(sender.isOn)")
print("Switch item is \(sender.tag)")
let changeWoord: WoordMO = woordeninlijst[sender.tag]
if changeWoord.isActive == true {
changeWoord.isActive = false}
else {
changeWoord.isActive = true
}
}
Any help is incredibly appreciated!
Related
I have a weird situation where I swipe a cell to grey it out and it greys every 4th or 6th cell instead of only the single cell that was swiped.
The tableview is initialized as follows:
func setupView() {
view.backgroundColor = .white
tableView.register(EntityCell.self, forCellReuseIdentifier: "entityCell")
tableView.separatorStyle = .none
tableView.dataSource = self
tableView.delegate = self
}
Here is my query to get the data:
func getEntities(taxId : String) {
dispatchGroup.enter()
db.collection("Taxonomy").whereField("entityId", isEqualTo: entityId).whereField("status", isEqualTo: 401).getDocuments { (orderSnapshot, orderError) in
if orderError != nil {
self.showError(show: "Error", display: orderError!.localizedDescription)
} else {
self.entitiesArray.append(contentsOf: (orderSnapshot?.documents.compactMap({ (orderDocuments) -> Order in
Order(dictionary: orderDocuments.data(), invoiceId: orderDocuments.documentID, opened: false)!
}))!)
self.dispatchGroup.leave()
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
Here are the standard override functions to populate the tableview:
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return entitiesArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "entityCell", for: indexPath) as? EntityCell else { return UITableViewCell() }
let entityRow = entitiesArray[indexPath.row]
cell.selectionStyle = .none
cell.setTaxonomy(entity: entityRow) // Setting up the cell with the array values
return cell
}
Everything is working fine upto this point. And finally here is the override func for swipe action:
override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let complete = UIContextualAction(style: .normal, title: "Verified") { (action, view, completionHandler) in
self.db.collection("Taxonomy").document(self.entitiesArray[indexPath.row].entityId).updateData(["status": 411]) { (error) in
if error == nil {
let cell = tableView.cellForRow(at: indexPath) as? EntityCell
cell?.changeStatus(currentEntity: self.entitiesArray[indexPath.row])
}
}
completionHandler(true)
}
complete.image = UIImage(named: "icon_approved")
complete.backgroundColor = UIColor(hex: Constants.Colors.secondary)
let swipe = UISwipeActionsConfiguration(actions: [complete])
return swipe
}
So I swipe right from the trailing edge of the cell and I see the underlying color and icon as expected. And the cell turns grey via this function via a protocol:
extension EntityCell : EntityStatusDelegate {
func changeStatus(currentEntity: EntityObject) {
entityCellBackground.backgroundColor = .systemGray4
}
}
The cell turns grey. And then I scroll down and I see every 4th or 6th cell is grey as well. Any idea what is going wrong? I am pretty flummoxed at this point.
Cells get recycled. You need either configure them completely or overwrite the prepareForReuse function of the cell or give each cell an unique reuseidentifyer so the tableview can recycle them.
(Last option is the worst as it cost a lot more memory)
Option 1:
Just set the backgroundcolor:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "entityCell", for: indexPath) as? EntityCell else { return UITableViewCell() }
let entityRow = entitiesArray[indexPath.row]
cell.selectionStyle = .none
cell.setTaxonomy(entity: entityRow) // Setting up the cell with the array values
cell.entityCellBackground.backgroundColor = (whatever the default color is)
return cell
}
The table cell is running shorter than it is supposed to be. (I use different background colour which shows difference width) The setting of cell is custom (only row height is change to 140). The playerCell class has nothing but some IBoutlets. Thanks.
(image: storyboard
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var count: Int
if playerBank.count == 0
{
count = 1
}
else{
count = playerBank.count
}
return count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! playerCell
if playerBank.isEmpty{
let p = Player()
playerBank = setInvalidPlayer(pBank: p, userInput: userInputPlayerName)
}
let playerInBank: Player = playerBank[indexPath.row]
passImageUrl = cell.setPlayerCell(p: playerInBank)
urlBank.append(passImageUrl)
let bgColorView = UIView()
bgColorView.backgroundColor = UIColor.red
cell.selectedBackgroundView = bgColorView
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
myIndex = indexPath.row
DispatchQueue.main.async {
self.performSegue(withIdentifier: "ShowPlayerInfo", sender: self)
}
}
My first guess is that, while you have a custom cell with custom outlets, that there are no layout constraints in place. So the items that you put into the storyboard are retaining their intrinsic values and not adapting to the device screen size.
If you add constraints to those outlets, especially enough to where the width of the cell can be determined based on the rest of the elements, then your cell should display full width.
I'm using following code to display an UIImageView in textFieldDidEndEditing:
let indexPath = IndexPath(row: 0, section: 0)
let cell = tableViewBodydata.cellForRow(at: indexPath) as! tvcell_Logbook
cell.imageViewArrow.isHidden = false
cell.imageViewArrow.image = UIImage(named: "same.png")
The code works perfectly on the iPhone X Simulator. But if im testing it on my iPhone X Device, the imageView isn't shown. The function is called correctly, I debuged it, but nothing happens. I reinstalled the App several times and also restarted the Device but nothing changed. Can anybody help me please?
Edit 1
I'm using this code in cellForRow:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell: tvcell_Logbook!
if indexPath.row == 0 {
cell = tableView.dequeueReusableCell(withIdentifier: "CellWeight", for: indexPath) as! tvcell_Logbook
cell.imageViewArrow.isHidden = false
cell.imageViewArrow.image = UIImage(named: "same.png")
}
...
return cell }
And this code in textFieldDidEndEditing:
func textFieldDidEndEditing(_ textField: UITextField) {
let indexPath = IndexPath(row: 0, section: 0)
let cell = tableViewBodydata.cellForRow(at: indexPath) as! tvcell_Logbook
cell.imageViewArrow.isHidden = false
cell.imageViewArrow.image = UIImage(named: "same.png") }
If your filename is Same.png:
UIImage(named: "Same.png")
How is your picture named at filesystem?
I have just finished adding a search bar to my TableView. It everything works perfectly, except the data displayed in the search results still shows the objects from the original, unfiltered array (although, when I click on the results they take me to the correct DetailView of the object for which I searched).
So the search logic is working, I just am not receiving a correct visual display of the search results.
I believe the issue arises in my cellForRowAt function, in which I attempt to determine whether the cell is filled with data from the original array or the search results. This line is marked with a caution error (the yellow one!) that reads 'Initialization of immutable value 'location' was never used; consider replacing with assignment to '_' or removing it'. However, I am unsure of how else to write this line.
Please see the relevant search code below (with the error line marked using a comment - it is almost at the very bottom of this code).
var locations = [Location]()
var searchController:UISearchController!
var searchResults = [Location]()
override func viewDidLoad() {
super.viewDidLoad()
searchController = UISearchController(searchResultsController: nil)
tableView.tableHeaderView = searchController.searchBar
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
self.tableView.reloadData()
}
func filterContent(for searchText: String) {
searchResults = locations.filter({ (location) -> Bool in
if let name = location.name {
let isMatch = name.localizedCaseInsensitiveContains(searchText)
return isMatch
}
return false
})
}
func updateSearchResults(for searchController: UISearchController) {
if let searchText = searchController.searchBar.text {
filterContent(for: searchText)
tableView.reloadData()
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searchController != nil && searchController.isActive {
return searchResults.count
} else {
return locations.count
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "cell"
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! LocationTableViewCell
// The following line is where I receive the error, as I attempt to determine whether the app should get the result from the filtered search result
let location = (searchController.isActive) ? searchResults[indexPath.row] : locations[indexPath.row]
cell.nameLabel.text = locations[indexPath.row].name
cell.thumbnailImageView.image = UIImage(named: locations[indexPath.row].image)
cell.locationLabel.text = locations[indexPath.row].location
cell.typeLabel.text = locations[indexPath.row].type
cell.accessoryType = locations[indexPath.row].isVisited ? .checkmark : .none
return cell
}
You're never using location. Change your code below that line to use it:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "cell"
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! LocationTableViewCell
let location = (searchController.isActive) ? searchResults[indexPath.row] : locations[indexPath.row]
//use the location variable you just set to set the cell's properties
cell.nameLabel.text = location.name
cell.thumbnailImageView.image = UIImage(named: location.image)
cell.locationLabel.text = location.location
cell.typeLabel.text = location.type
cell.accessoryType = location.isVisited ? .checkmark : .none
return cell
}
I'm working on a project in swift 3.0 where I have a UIView inside a UITableViewCell. For some reason once a row is been selected the view gets disappear, and once a a new row is been selected the view of the previous cell shows up and the view of the newly selected one gets disappear.Name of the view that gets disappear is redView(reference of the code bellow). My code and UITableView delegates as follow.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let backgroundView = UIView()
backgroundView.backgroundColor = UIColor.clear
cell.selectedBackgroundView = backgroundView
let data = self.mediaList[indexPath.row] as! NSDictionary
let redView = cell.viewWithTag(TABLE_CELL_TAGS.redView)!
let reducedPriceLabel = cell.viewWithTag(TABLE_CELL_TAGS.reducedpricelable) as! UILabel
Utils.setTableCellLabelText(cell: cell, labelTag: TABLE_CELL_TAGS.title, text: data["title"] ?? "title...")
if let reducedPrice = data["mediaValue"] as? Int{
reducedPriceText = "$\(String(reducedPrice))"
redView.isHidden = false
reducedPriceLabel.isHidden = false
}else{
redView.isHidden = true
reducedPriceLabel.isHidden = true
}
Utils.setTableCellLabelText(cell: cell, labelTag: TABLE_CELL_TAGS.reducedpricelable, text: reducedPriceText)
return cell;
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let mP3ViewController = self.storyboard?.instantiateViewController(withIdentifier:"MP3ViewController") as! MP3ViewController
mP3ViewController.mediaDetails = mediaList[indexPath.row] as? NSDictionary
self.navigationController?.pushViewController(mP3ViewController, animated:true)
}
Go to the storyboard setting of tableViewcell set selection to None. then I think it will work for you.
Try this and let me know.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let mP3ViewController = self.storyboard?.instantiateViewController(withIdentifier:"MP3ViewController") as! MP3ViewController
mP3ViewController.mediaDetails = mediaList[indexPath.row] as? NSDictionary
self.navigationController?.pushViewController(mP3ViewController, animated:true)
}