I was trying to create a custom TableView Cell in Storyboards. The correct data shows when the ViewController is loaded. However, when I start scrolling back and forth, the data is showing up in random cells, not in the right place. I was also trying to make the text of a Right Detail cell bold programmatically like this:
if dayOfWeek!-1 == indexPath.row {
cell.textLabel?.font = UIFont.boldSystemFont(ofSize: (cell.textLabel?.font.pointSize)!)
cell.detailTextLabel?.font = UIFont.boldSystemFont(ofSize: (cell.detailTextLabel?.font.pointSize)!)
}
However, similar things happened: the bold seems right at first and the text are bolded in random cells. Any idea how to fix this? Thanks!
class CustomTableViewCell: UITableViewCell {
override func prepareForReuse() {
// your cleanup code
}
}
in cell for indexpath
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: CustomTableViewCell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath) as! CustomTableViewCell
if dayOfWeek!-1 == indexPath.row {
cell.textLabel?.font = UIFont.boldSystemFont(ofSize: (cell.textLabel?.font.pointSize)!)
cell.detailTextLabel?.font = UIFont.boldSystemFont(ofSize: (cell.detailTextLabel?.font.pointSize)!)
}
return cell
}
You have to reload the tableview when you have called it.
The random shown data is due to the property undertaken by the various cell from the each other.
You have faced these type of problem when you are using the multiple tableview on the single view.
Hence the cell having the elements wrongly considered the properties, which can be solved by refreshing the table view which is "RELOAD".
If the Data coming is from the API , then it would be an advantage, put the Response data to your main array and Reload the table view .
Related
I need to place a radio button in tableview custom cell. whenever user clicks the tableview cell or button then radio button needs to work. I tried by using below code but didn't execute well.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:TableViewCell = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as! TableViewCell
cell.country.text = self.animals[indexPath.row]
cell.selectionStyle = UITableViewCellSelectionStyle.none;
if selectedRows.contains(indexPath)
{
cell.radioButton.setImage(UIImage(named:"check.png"), for: .normal)
}
else
{
cell.radioButton.setImage(UIImage(named:"uncheck.png"), for: .normal)
}
return cell
}
Here's a great solution for creating radio buttons in a UITableView using a storyboard that requires zero code - and has 2 great Cool Tips!!
Make sure your table view is set to Single Selection, and to use Static cells.
Add a Basic cell, set the image to be your unchecked button image, and make sure the selection style is Default
Cool Tip # 1: Click on and select the cell's image view, and then set it's highlighted image to be your checked state. When the cell is highlighted or selected, the image view within will change to show its highlighted state.
Cool Tip # 2: Next, drag a UIView into the cell's content view, behind the text label. As you're using a basic cell, you won't be able to drop it directly into the cell, you'll need to drag it into onto the Document Outline on the left instead. Then hook this up to the cell's selected background view outlet. When a cell is selected (or highlighted), this view will be displayed in the background. In this case, we're going to use it to prevent the grey background appearing, so set its colour to Clear. Note that it doesn't matter what size the view is, and there's no need to set any constraints - it's automatically sized to match the cell at runtime.
Finally, duplicate this cell and change the text for each of your radio button options. Build and run, and you have code-free radio buttons!
In your TableViewCell class why don't you create a data source element and override the didSet for it. also in your data source for the UITableView I would recommend an array of something more than just a String.
I haven't compiled the below so this is just an idea.
import UIKit
class TableViewCell : UITableViewCell {
var data: Animal? {
didSet {
self.country.text = data.description
if (data.isSelected) {
self.radioButton.setImage(UIImage(named:"check.png"), for: .normal)
} else {
self.radioButton.setImage(UIImage(named:"uncheck.png"), for: .normal)
}
}
}
}
in your view controller you will of course have to set the isSelected property whenever a row is tapped.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
var animal = self.animals[indexPath.row]
animal.isSelected = !animal.isSelected
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:TableViewCell = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as! TableViewCell
cell.data = self.animals[indexPath.row]
}
and for your Animal maybe something like this:
struct Animal {
var description: String
var isSelected: Bool
}
I have uitableview with 10 images in rows in my Xcode swift project. I use this code to show 10 images in rows in my uitableview:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: String(format: "Cell0", indexPath.row), for: indexPath)
var imageV = UIImageView()
imageV = cell.viewWithTag(5) as! UIImageView
imageV.image = UIImage(named:"image\(indexPath.row + 1).png")
But when I scroll my uitableview freezing very very very hard. Why is this happening? And How to fix it?
Create a custom cell
class MyCustomCell: UITableViewCell {
#IBOutlet weak var imgView: UIImageView!
}
In your storyboard, set the class of the cell to MyCustomCell and give it an identifier say cell.
Then, update your cellForRow method as below
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MyCustomCell
let imageName = "image\(indexPath.row + 1).png"
cell.imgView.image = UIImage(named: imageName)
return cell
}
UPDATE
Create a new swift file called MyCustomCell.swift
In storyboard, set your cell's class to MyCustomCell
Add a UIImageView in your cell
Connect the #IBOutlet
Set your cell's identifier
Update your cellForRow method
The tableview is lagging and freezing on the scrolling because of how CellForRow works. Essentially, the OS does not save cells that are displayed. For example, rows 1-2-3 are displayed on the screen and have gone through cellForRow. Rows 4 is about to be displayed and row 1 will be removed off the screen. Row 4 will go through cellForRow for it's information to be displayed, and once row 1 is off the screen it will be removed from memory. So if you then scroll back to row 1, it will go through cellForRow and reload the image. So in this case your tableview is constantly loading images from the bundle as you scroll up and down.
Your solution might be to preload all your images and have them in an array so that the OS doesn't have to spend time loading the images repeatedly. Another way to go about might be to create a custom cell and simply have the cell handle loading it's own image by providing it the image name, rather than have the tableview manage the loading of every single's cell's image repeatedly. This would also clean up your cellForRow.
For example: make a new tableViewCell called imageCell which has an imageName property that could be an String. Once the cell is made, you simply pass it the string of it's image in cellForRow, and when the imageCell is created, have it load it's own image through this string in it's awakeFromNib.
let cell = tableView.dequeueReusableCell(withIdentifier: String(format: "Cell0", indexPath.row), for: indexPath)
to
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as CustomCell
cell.imageView.image = UIImage(named: "yourimagename")
Don't change your reusable identifier everytime. This is causing freezing in your case. Moreover create custom cell for adding UIImage.
I would like to confirm the approach I took to solve an issue with dequeuing custom cells in a UITableView as it scrolls such that the cells do not contain the old cell's data...
The app that contains a UITableView with custom UITableViewCells ("CustomCell"). Each CustomCell contains a UIStackView with one or more custom views via a nib ("CustomView"). I reuse the CustomCell as follows:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(ReuseIdentifierCustomCell, forIndexPath: indexPath) as! CustomCell
configureCell(cell, atIndexPath: indexPath)
return cell
}
The issue was that the cell would contain "old" data as the cell was being reused. To fix this, I override the prepareForReuse method in CustomCell as follows:
override func prepareForReuse() {
super.prepareForReuse()
for case let view as CustomView in stackView.subviews {
view.removeFromSuperview()
}
}
Then in layoutSubviews, I add the subviews back in:
override func layoutSubviews() {
super.layoutSubviews()
if stackView.subviews.isEmpty {
addCustomViewsToCell()
}
}
Performance seems fine thus far, but curious if this is a proper approach or if I will run into issues with scale in the future. I have not been able to find another workable approach thus far.
Thanks
Your code to reuse cells is correct. A common approach is to configure your cell's data within the cellForRowAtIndexPath function by setting a variable or calling a function on your custom cell:
let cell = tableView.dequeueReusableCellWithIdentifier(ReuseIdentifierCustomCell, forIndexPath: indexPath) as! CustomCell
cell.data = myData[indexPath.row] // where myData is an array of type [Data]
return cell
Your cell would be in charge of its own layout to display the new data:
var data: Data {
didSet {
// configure and refresh your UI here
}
}
I suspect your issue has to do with your configureCell function. If you can, move this code into your cell's logic instead. This will be cleaner and easier to understand.
As far as performance, you might be fine now if your stack views don't have much content in them, but if they continue to grow in complexity you might see frame rate drops on older devices.
How can I achieve this screen with UITableViewCell and UITableViewController. With table section and header. Some ideas to achieve this?? Thanks!
What have you tried so far?
Your question seems a little broad.
You will need a set of custom UITableViewCell Subclasses, which you design in nibs.
To make the cells seem apart from each other, resize the content size of the Cells, and make the cell background another color.
Create a Segmented Control and add it to the Tableviews HeaderView.
For the FooterView it seems like this is some kind of subclassed Tabbar.
Easiest way to customise it in such a way, would be to create a View, and add buttons to it. Add this View as Subview to your TableViewController.
Have 2 UITableViewCell's one for each type i.e. 1 for showing the image and text and another for showing just the text.
Then in the cellForRowAt delegate method determine which to type to use based off the object you are data binding it to.
Example:
public final func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let customObject = customObjects[indexPath.section]
switch customObject.type {
case .imageAndText:
if let cell = tableView.dequeueReusableCell(withIdentifier: ImageAndTextCell.identifier, for: indexPath) as? ImageAndTextCell {
cell.customObject = customObject
return cell
}
case .text:
if let cell = tableView.dequeueReusableCell(withIdentifier: TextCell.identifier, for: indexPath) as? TextCell {
cell.customObject = customObject
return cell
}
}
return UITableViewCell()
}
I am trying to get a custom tableView cell with a textView inside working in my tableView. I have made a custom UITableViewCell with a textView inside it.
I can get the custom made UITableViewCell with the textView inside to appear in the UITableView.
I can click inside the textView to type something, but when I finish typing and click on another tableViewCell, the first tableViewCell with the textView inside disappears. After disappearing, it becomes an empty tableViewCell. XCode gives this message:
"no index path for table cell being reused"
However, when I scroll away in the tableView and scroll back to the empty tableViewCell, it reappears.
I don't know how to keep the tableViewCell from disappearing. It seems like the answer has something to do with using the restorationIdentifier inside of UITableView, but I'm not sure how to use it. In the docs, it says to use restorationIdentifier for state preservation.
Here is the relevant code I have:
inside ViewDidLoad():
tableView.registerClass(PhotoAndRateTableViewCell.classForCoder(), forCellReuseIdentifier: ReuseIds.reviewCell)
tableView.registerNib(UINib(nibName: "PhotoAndRateTableViewCell", bundle: NSBundle.mainBundle()), forCellReuseIdentifier: ReuseIds.reviewCell)
inside cellForRowAtIndexPath:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var section = indexPath.section
let cell = UITableViewCell()
var cell = tableView.dequeueReusableCellWithIdentifier(ReuseIds.reviewCell, forIndexPath: indexPath) as PhotoAndRateTableViewCell
cell.selectionStyle = UITableViewCellSelectionStyle.None
return cell
}
You're misusing the dequeue procedure:
var cell = tableView.dequeueReusableCellWithIdentifier(ReuseIds.reviewCell, forIndexPath: indexPath) as? PhotoAndRateTableViewCell
if (cell == nil) {
cell = PhotoAndRateTableviewCell();
}
You want to reuse a cell if available, or create a new one if not. In your case, you're creating a cell every time (of the generic class) and then attempting to dequeue a cell from your custom class (which has never been created)
As far as preserving the data, you need to implement the prepareForReuse method in the table cell which should clear whatever index specific data was contained in the cell. Then in cellForRow you can re-set the data for the cell for re-appearance