Removing all subviews from a UITableViewCell except imageView - ios

I am creating a custom cell and I add subviews to it for text mostly. At first the subviews were not getting deleted when the cell was reused, so the text would overwrite and blot really bad. Then I added this for loop to the function and it solved my problem except that it also completely removes my imageView and it never gets re-added, so my whole tableview is missing the image that is supposed to be associated with each cell.
The if statement didn't work, but I didn't explicitly use cell.addSubView() as i did for the cell labels, so I am wondering if that has something to do with it. I have googled and found that most people are saying this worked for them, but I just cannot seem to figure it out.
Why does this remove my images, why won't they come pack like the other subviews, and how can I fix this?
I have the following code:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! UITableViewCell
for subView in cell.subviews {
if subView as? NSObject != cell.imageView {
subView.removeFromSuperview()
}
}
var statusImage = UIImage(named:imageConfigration(indexPath.row))!
cell.imageView?.image = statusImage
// ...
}

Give your imageView a tag in storyboard or xib or programmatically what you are using. Now in the for loop of subviews check if tag of the subview is equal to tag to imageview dont remove it.
Also another option to solve this if it fits your requirement is to hide all the elements added to cell except imageview. That will be much faster then looping in subviews and removing it you never know what all subview are attached to cell other then you added by iOS but thats if it fits your req. Let me know in case of any concern
This how you can do this
cell.textLabel.hidden = YES;

Related

How to create tableview cells without using prototype cells?

In my tableview, every cell will be different and determined by a JSON response from server. And there will be infinite possibilities. So defining a prototype for each type of cell is not possible.
For example, one cell will have labels and buttons, another cell have images and buttons in different orders.
How to achieve this dynamic structure in tableview cells?
Currently what I am doing is: adding views as subview in cellForRowAtIndexPath but scrolling is very laggy this way.
How to achieve this without affecting performance this much
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! MyCell
for myview in data[indexPath.row].myviews{
cell.addSubview(myview)
}
return cell
}
If you're using a table view then your content is going to scroll vertically, right?
There is a physical limit to the amount of UI that you can put horizontally. Limited by the screen size.
So I'm guessing your UI parts are being laid out vertically in the cell?
So instead of laying out a button, label, image, another button, and a text field vertically in a cell...
Create a cell type called ButtonCell, LabelCell, ImageCell, MultiLineLabelCell, TextFieldCell, etc...
So now, instead of creating one cell with all these elements added. You instead create multiple cells each containing one type of UI. Now you can dequeue your cells in any particular order (driven by your JSON) and won't lose the performance.
The only solution I see is to have empty cell and add/remove subviews as needed. But you should add new subviews to a cell only if you did not add them before.
For example:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! MyCell
if cell.contentView.viewWithTag(1) == nil {
let label = UILabel()
label.tag = 1
cell.contentView.addSubview(label)
}
let label = cell.contentView.viewWithTag(1)
// label config there
return cell
}
Also don't forget to add subviews to cell's contentView not to cell itself.

Image inside tableViewCell automatically zooms when touched, why?

I have no idea why, but when I touch a cell, image inside it kind of zooms and is partially of screen. Below you can see, the first row looks like it should and the second row was selected and now looks zoomed.
There is not much code, only ViewController and TableViewCell that both have minimum required code.
EDIT: Here's how I add cells, and there is no didSelectAtRow.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! TableViewCell
cell.myImage.image = UIImage(named: "uk.png")
return cell
}
EDIT2: Initially my imageView constrains where 0 to all margins, so that whole cell would be only image. When I made image quite small, none of zooming happens, so maybe I am doing something wrong with constrains?
Final Edit - Problem Solved
Not sure, how that zooming happened, but in my case trying different constrains solved the problem.
It is because your tableview is reuse its cell
First set the constraints of the cell.
and
also implement the
the code in cellForRowAtIndexPath with
if(cell == nil)
{
cell = [[UITableViewCell alloc] init];
}
also share your code for didSelectRowAtIndexPath

Why using SDWebImage in a UITableViewCell triggers ImageViews not to render properly?

I have a UITableViewController containing my own cells that I dequeue in cellForRowAtIndexPath.
After dequeuing, I configure the cell and reload, asynchronously, the image for that cell.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCellWithIdentifier("PeopleCell", forIndexPath: indexPath) as? PeopleListViewCell {
cell.configureCell(headImageUrl)
}
}
In my PeopleListView class,
func configureCell(img:NSURL) {
if headImageView == nil { // to avoid allocation memory if not used
headImageView = UIImageView()
addSubView(headImageView)
}
headImageView.sd_cancelCurrentImageLoad()
headImageView.sd_setImageWithURL(headImageUrl)
}
It works fine at the first loading and also while scrolling.
But when I push another viewController after
didSelectRowAtIndexPath
and come back to the list after the
dismissViewController()
I end up with a weird effect on my UIImageView , it's kind of a stacked or ghost image effect..
I'm having a hard time to figure out where is even triggered as when I m coming back from the viewController, cellForRowAtIndexPath is not called.
This actually has nothing to do with asynchronous image loading.
The images I had was displayed within circles, with a cornerRadius.
Somehow, it was displayed without any problem at first load...
The issue here is I simply forgot the
headImageView.layer.maskToBounds = true
The result I got before setting maskToBounds to true was that I had the feeling that multiple images were located within the headImageView (UIImageView). If you ever have some artefacts like that, I hope this question/answer will help you.

Passing data to custom UITableViewCell with adding subviews

I'm passing data to a custom UITableViewCell and based on that data I want to show or hide a dynamically added subview. I'm reusing a cell which is created in the storyboard. Everything is working as expected, until some of the cells are reused, for example while scrolling it will "randomly" hide or show the dynamic added subview.
What I need
I need a way to set the data of a cell through a method (setData), adding a dynamically created subview, while allowing a cell to be reused without creating glitches in its appearance, in particular the added subview as well the cells state.
Problem
I don't know where I should create the subview, so it doesn't have to be recreated when the cell is reused and so it won't bug when I want to hide or show it in the setData method. As well having access to the IBOutlet storyboardLabel while creating the new subview.
CustomTableViewCell
class CustomTableViewCell : UITableViewCell {
var data: DataItem?
var customSubview: UIView?
#IBOutlet weak var storyboardLabel: UILabel!
//setting the data of a cell and adding the subview
func setData(DataItem data) {
// adding the view
let customSubview = UIView.init(...)
customSubview.bounds = storyboardLabel.bounds
customSubview.hidden = data.showSubview
self.contentView.addSubview(customSubview)
}
}
Adding the cell
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("storyboardTableCell") as! CustomTableViewCell
cell.setData(self.data[indexPath.section][indexPath.row] as! DataItem)
return cell
}
Everything is working as expected, until some of the cells are reused...
Nothing is working as expected: you are adding object to a cached UITableViewCell, and of course, when you are passed that cached cell again on a subsequent cellForRowAtIndexPath, you are adding new objects.
Consider using a collection of views in IB, each satisfying your cell organization, thus saving adding subviews programmatically.
You need to clean up your cell.
Either remove everything you have added in your cellForRowAtIndexPath
You can use tags and viewWithTag if you want to refrain from re-adding already existing views
Or implement prepareForReuse()
You can find an example (and a similar discussion) on this Stack Overflow post.

Custom TableViewCell not Displaying Accessory

I've done many apps with simple tableviews and I'm comfortable with them. I've never used a custom tableViewCell until today. I started with a really custom cell with two labels and that renders normally. I can populate my two labels with my data, no problem. I thought it would be equally easy to add the standard checkmark using:
cell.accessoryType = .Checkmark
My cells render the labels properly but I don't get a checkmark. Is there something extra I need to do to render an accessory type with a custom tableViewCell?
edit: I tried to not just use a default accessoryType. I created an image, an imageview, and set cell.accessoryView to that view and that doesn't display either. Obviously I'm missing something in my custom cell
try this code:
func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
// your cell coding here and set cell accessory view checkmark
cell.accessoryType = IUTableViewCellAccessoryType.Checkmark
}
UITableViewCell consist of 2 subviews:
contentView
accessoryView
When you are creating your own custom cell (that extends UITableViewCell) add your views to contentView. (See docs)
It is possible that you have added your views directly to UITableViewCell and in this case you are drawing your subviews on top of accessoryView.

Resources