UItableViewCell imageview changing on select - ios

I am loading in a list of facebook users using webcache and it works fantastically. Until you select one of the cells then it seems to either change the content mode, or more likely it changes the size of the uiimageview frame, but based on the actual size of the picture. for clarity here are some screens
here it is loaded
http://img.photobucket.com/albums/v246/homojedi/Screenshot20120727114807.png
and on selection of some of the images as you can see they seem to jump to their original aspect.
http://img.photobucket.com/albums/v246/homojedi/Screenshot20120727114827.png
as expected if i scroll them off screen and back to them they restore to what they were at the start.
It's baffling. The only thing i have not attempted is subclassing the uitableView and setting its layout subview there. short of that is there anything else i can do?
EDIT: code requested
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// typically you need know which item the user has selected.
// this method allows you to keep track of the selection
_indexPath = indexPath;
[_indexPath retain];
}

I've face exactly the same issue as you,and I fix
the issue is cause by you named your imageView "imageView"
i don't know why
if you change your imageView name like "m_imageView"
the issue fixed
It's all about naming!

I have come across this problem but I have no imageView property inside my custom UITableViewCell.
In fact I did make a stupid mistake by connecting an extra IBOutlet from my imageView object to the default imageView property of UITableViewCell. It is because I initially named my image view imageView, but then I changed it and forget about the outlet.
After removing the outlet, everything works fine.

Just in case someone else, like me, come upon this issue where non of the above worked.
I too had named my UIImageView: imageView. But, for some reason, even after renaming it, the problem persisted.
I tried everything I could think of, Reset Simulator, Clean Project, adding removing constrains....
As it turns out, simply deleting the UIImageView from the Storyboard and dragging a new one fixed it.
Couldn't have been a precompiled issue because I cleaned the project. Go figure.

I was having this issue and I solved it!!!
Check to make sure you synthesized the imageView property in your custom TableViewCell.
I forgot to synthesize a property (resulting in no getter/setter for the IBOutlet).
This topic is old but hope that helps someone else!

// reason for this problem is UITableView cell's imageview initially has a default size later on it resize it self on select so following cab be a solution for this: (Using AFNetworking to set image/ You can adjust accordingly)
__weak UItableViewCell *cellTemp = cell;
[cell.imageView setImageWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:strURL]]
placeholderImage:[UIImage imageNamed:#"placeholder"]
success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image)
{
cellTemp.imageView.image = image;
CGRect frameRect = cellTemp.imageView.frame;
frameRect.origin.y = (cellTemp.frame.size.height - image.size.height)/2;
frameRect.size.width = image.size.width;
frameRect.size.height = image.size.height;
cellTemp.imageView.frame = frameRect;
[cellTemp layoutSubviews];
// this will fit your cell's label
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error)
{
}];

I believe your problem is due to the UIImageView. You should be setting the image once - cell.imageView.image = myImage. Do not set a highlightedImage. Set the contentMode to maintain the aspect ratio of your image: cell.imageView.contentMode = UIViewContentModeScaleAspectFit;, and verify that the contentStretch rect is 0,0,1,1 (the default).
It is possible the tableView is changing the contentMode of the UIImageView or its frame when it gets selected (for who knows why reasons). I would add NSLogs to both willSelectRowAtIndexPath and didSelectRowAtIndexPath, showing the same information: the imageView frame, the contentMode value (as an integer), etc. Somehow one or more of these values is changing on selection.

Adding to the answers regarding the naming issue:
As it has been said, the problem with the image view persists even after renaming it. But it is not required to delete the UIImageView from your xib or storyboard. You can simply ctrl-click the image view and remove the connection to property imageView that still exists.
The reason the link to imageView still exists seems to be that the imageView property still remains available after you delete it in your code. It's still there because it is inherited from UITableViewCell.
One last hint that sounds stupid but took me a few minutes to realize: Obviously all code using property name imageView will still work but will result in strange behavior! So double check if there's no code left using the old property name.

I had the same issue, and even after trying all the previous answers none of them worked out. Later i found out that the UITableViewController had multiple unused Outlets, so deleting the unused Outlets fixed the problem.

As requested by sebastian-Luczak I did come up a solution for resizing, but now there is an image quality inconsistency, it gets higher resolution only when you touch it, strange but not as bad or noticable, anyway here is the code.
N.B i Am using SDWebImage to load the pictures asynchronously
[cell.imageView setImageWithURL:[NSURL URLWithString:path] placeholderImage:[UIImage imageNamed:#"Icon.png"]success:^(UIImage *image)
{
cell.imageView.image = [image resizeImage:image newSize:CGSizeMake(38, 38)];
} failure:^(NSError *error)
{
}];

// If you subclass UITableViewCell you can get rid of this problem
- (void)layoutSubviews {
[super layoutSubviews];
self.imageView.bounds = CGRectMake(10,5,65,65);
self.imageView.frame = CGRectMake(10,5,65,65);
self.imageView.contentMode = UIViewContentModeScaleAspectFit;
}

Related

Collapse UIImageview in UITableview cell, when it doesn't return an image

Summary of the problem
I have a UITableView in which I want to Collapse it's UIImageView cell part, whenever it doesn't return an image, as seen below
first image of tableview cell (the expected result)
second image of tableview cell (the no image result)
Background including what I've already tried
Below is the piece of code that I have been working on. Also notice that I'm using SDWebImage to get and set the image in the app (any method in tableview delegates, SDWebImage protocols etc that I'm missing just point me),
The comment out part is what I have done, i.e. used constraints to try
the collapse of UIimageView not it messes up the whole tableView upon
scrolling
Code
Here is piece of code I'm working on,
[cell.i_imageView sd_setImageWithURL:[NSURL URLWithString: item.PostimageUrl] placeholderImage:[UIImage imageNamed:#"no-image"] options:SDWebImageRefreshCached completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
if(!image)
{
//cell.i_imageView.hidden = YES;
NSLog(#"why no image des:%#",error);
NSLog(#"why no image url:%#",imageURL);
}
// cell.imageHolderAspectConstraint.active = TRUE;
// cell.imageHolderZeroImageConstraint.active = FALSE;
// }
// else
// {
// cell.imageHolderAspectConstraint.active = FALSE;
// cell.imageHolderZeroImageConstraint.active = TRUE ;
//
// [cell layoutIfNeeded];
// [cell setNeedsLayout];
// }
[cell.i_imageView sd_removeActivityIndicator];
}];
Any help in this matter is highly appreciated, cheers.
Edit
Here is the image of storyboard section, where do I need to embed stackview
Add your ImageView in StackView. Now hide your ImageView when image is not available.
Note : UIStackView automatically handle height of cell.
Edit:
As of now your UI is something like this.
Now select your image holding view and click on embedded in and select UIStackView.
Now assign the same constraints that you have given to holding view to stackView.
Now your hierarchy is like below
Finally you need to do below code in CellForRow:
cell.vImageHoldingView.hidden = !image;
Embed if in a stackView
Attach stackview anchors to the desired anchors
Hide image view if needed.
StackView automatically collapses its hidden arrangedSubViews
Note: If you set the image nil, it will collapse again, because stackView manages imageView height according to its image.
If there is no image, make the ImageView height to 0. Remaining things will get handled if it has a proper constraints.
make picture bottom constraint as outlet . Like this
var bottomViewConstraints: NSLayoutConstraint!
and give value on collapse and expand. like this
bottomViewConstraints.constant = 0 // expand
bottomViewConstraints.constant = 60 // collapse

Understanding the mechanism used by SDWebImage when used in a UITableView

This question is for my understanding as my code is working fine.
I have looked inside SDWebImage, but it's fairly large and I can't pinpoint how the mechanism I'm questioning works.
OK, let's say I have a tableview full of UIImageViews (one inside each cell), and I call the SDWebImage Category/Extension on each of them to go and lazy load an image from the web.
What mechanism is employed to update the cell as it's on screen with the newly downloaded image, without reloading the tableview?
I ask this as I was surprised to see that when using SDWebImage Extension each of my cells' imageViews image popped into existence as soon as it's corresponding image had downloaded.
I was under the impression that I'd have to reload the tableView, but instead each cells imageView 'automagically' updated when the image was available!
How does this work? Does SDWebImage keep a reference to each cell/imageView it's working with?
SDWebImage inserts the loaded image into the UIImageView instance on which the load has been queried.
With UITableViewCell you have to be a bit tricky to avoid non-relevant images in your cells, here is why:
Imagine you requested the image for URL of the first item (firstURL) on the topmost visible cell.
You scroll down your table, and following happens:
the former topmost cell gets reused and appears on the bottom of the table.
the image is queried for URL of the last cell (lastURL).
firstURL loading completed, and corresponding image is inserted into the image view of the last cell, because it was the image view for which firstURL loading has been queried.
lastURL loading completed, and corresponding image is inserted into the image view of the last cell.
Steps 3 and 4 might look like fast blink in the image view.
To avoid that, you need to address the cancellation of the previous download in prepareForReuse method implementation of the UITableViewCell subclass.
e.g.
- (void)prepareForReuse {
[super prepareForReuse];
[self.imageView sd_cancelCurrentImageLoad];
self.imageView.image = <placeholder image>;
}
If you are referring UIImageview in UITableviewCell then you can check that SDWebImage is one kind of UIImageView class, so no need to describe which image view refers for downloaded image, as its self identify
Let me show you once..
as we request for image inside cell like this.
[cell.imgBrand sd_setImageWithURL:url completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
if (error != nil) {
NSLog(#"%#", [error localizedDescription]);
}
}];
When first line executed, it will call method inside UIImageView+WebCache.h class.
as you can see that class itself UIImageView
#implementation UIImageView (WebCache)
Class For SDWebCache UIImageView

flashy images from previous cells using sdwebimage ios?

I used SDWEBImage library to show images in scrollview under the tableview.
My problem is, images load completely but when I scroll tableview flashy images from previous cells or duplicate images show in Imageview. I programmatically created an imageview like below:
My code is below:
for (NSString *stringurl in [[[Arr objectAtIndex:indexPath.row]valueForKey:#"sports"]valueForKey:#"image"]) {
UIImageView *yourImageView =[[UIImageView alloc] initWithFrame:CGRectMake(x,10,40,40)];
NSURL *urlimg=[NSURL URLWithString:stringurl];
[yourImageView sd_setImageWithURL:urlimg
placeholderImage:[UIImage imageNamed:#"placeholder"] options:indexPath.row ? SDWebImageRefreshCached : 0];
[cell.arenaimgscroll addSubview:yourImageView];
x = x + 50;
if (stringurl==NULL) {
cell.arenaimgscroll.hidden=YES;
}
else{
cell.arenaimgscroll.hidden=NO;
}
}
Just a short overview, So you get your answer
UITableView is highly optimized, and thus only keep On-screen visible rows in memory. Now, All rows Cells are cached in Pool and are reused and not regenerated. Whenever, user scrolls the UITableView, it adds the just-hidden rows in Pool and reuses them for next to be visible rows.
So, now, coming to your answer
When you scroll your UITableView, UITableView datasource method gets called again for every indexPath, thus dequeueReusableCellWithIdentifier gives you cached cell, which already have UIImageView added, but
you add UIImageView again to it(SOURCE OF ERROR)
Better solution will be
to add imageView in interface builder
or
you can check, if imageView already added and then skip the step of adding it again
UPDATE:
NOTE : This solution is not optimized as you are already not reusing image elements, but will resolve your problem.
Add this script above your for loop, this is for clearing older images(that got reused) from your scrollview(arenaimgscroll) :
[cell.arenaimgscroll.subviews makeObjectsPerformSelector: #selector(removeFromSuperview)];
for (NSString *stringurl in [[[Arr objectAtIndex:indexPath.row]valueForKey:#"sports"]valueForKey:#"image"]) {
//YOUR CODE
}

Image View in Auto Layout using SDWebImage in Storyboards

I'm having no luck getting an image and its UIImageView to show up the correct size in my custom UITableViewCell. The image is correct, but its place in the UITableViewCell is not, and isn't even close.
I don't have enough reputation points to post images sadly.
I have all the suggested constraints Xcode 6 added or suggested, but the image is showing up huge and in front of everything in my UITableViewCell.
Here's the only code I have related to it.
ViewController.m
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 600.0;
NSString *imageURL = [NSString stringWithFormat:#"%#", standardResolutionLocal.url];
__weak UITableViewCell *wcell = api2Cell;
[wcell.imageView
sd_setImageWithURL:[NSURL URLWithString:imageURL]
placeholderImage:[UIImage imageNamed:#"320x180.gif"]
];
CustomTableViewCell.m
- (void)layoutSubviews {
[super layoutSubviews];
[self.imageViewPic setTranslatesAutoresizingMaskIntoConstraints:YES];
}
I'm using iOS 8, Xcode 6, and SDWebImage via CocoaPods. Any help would be appreciated, thanks!
Select your image view and modify the Content Mode as desired - perhaps Aspect Fit will scale it appropriately. If it appears positioned correctly but continues to extend outside the image view bounds, enable Clips to Bounds.

UITableViewCell showing UIImageView in some cells and different cells when scrolling - in use with CoreData and NSFetchedResultsController

I have a simple application whereby a UITableView is populated by a user tapping on an item in the UINavigationBar and then getting taken to another view to fill in UITextFields and UITextView. When the user clicks save, the information is saved to Core Data and then represented in this UITableView with the use of NSFetchedResultsController.
One of the attributes is a "Notes" attribute on a "Transaction" Entity. Filling in the Notes in the UITextView is completely optional, but if the user adds in a note, I want to show a custom image that I've created on the cell for the entry that has the note.
When the app is run in this version alone (so deleted and installed with this developer release), it works very well and the cells show the notes only for the cells that have the notes. However, when updating from a previous version of the app, this is where the problem occurs.
The previous version of the app didn't have a Notes attribute and so I used CoreData lightweight migration to set up a new model with a Notes attribute. That part works.
The Problem
Because of the reusing of cells, I'm noticing that when I've updated from an old version to this new version, none of the cells have the custom image and that's good because the notes doesn't exist. However, if I go in and add a new entry with a note and then scroll through my UITableView, I notice the cells start showing the custom image randomly, based on scrolling. So it disappears from one cell and shows up on another. This is a big mis-representation for my users and I'm not quite sure what to do to fix this.
In my cellForRow I have the following code:
self.pin = [[UIImageView alloc] initWithFrame:CGRectMake(13, 30, 24, 25)];
self.pin.image = [UIImage imageNamed:#"pin"];
self.pin.tag = 777;
if (!transaction.notes) {
dispatch_async (dispatch_get_main_queue (), ^{
[[customCell viewWithTag:777] removeFromSuperview];
});
}
if ([transaction.notes isEqualToString:#""] || ([transaction.notes isEqualToString:#" "] || ([transaction.notes isEqualToString:#" "] || ([transaction.notes isEqualToString:#" "]))))
{
[[customCell viewWithTag:777] removeFromSuperview];
}
else
{
[customCell addSubview:self.pin];
}
So the first if statement is to check whether the notes exist and that returns true when updating from an old version of an app to this version. The second if statement just checks if the value of the notes is equal to a few spaces and if so, then to remove the note.
I just can't figure out what's going on here.
Possible Solution
In the same UITableView cell, I also have a green/red dot UIImageView which is displayed depending on whether the user selected a Given or Received Status when adding a new entry. With this in mind, one image is ALWAYS displayed, whether it's the green or red dot. So what I'm thinking about here is creating a transparent square and just changing the if statement to say "If note, show pin image and if not, show transparent image".
That feels a bit like a hack though and I'd prefer a proper way to fix this.
Any thoughts on this would really be appreciated.
First of all, bad practice to allocate views in cellForRow. If you really need to allocate views in cellForRow do it just when it's needed, in your case in the else statement.
Second, do not use dispatch_async to dispatch on main thread if you are already on main thread (cellForRow it's on main thread).
The above points are just some suggestions for performance improvement.
As a solution of your problem, I would create a custom UITableViewCell and in it's method prepareForReuse I would remove the imageView.
EDIT
YourCustomCell.m
- (void)prepareForReuse {
[super prepareForReuse];
[[self viewWithTag:YOUR_TAG] removeFromSuperview];
}
This is a straightforward implementation, but you have to take in consideration that is more expensive to alloc/dealloc the UIImageView than keep a reference to the image and hide it when you don't need it. Something like:
YourCustomCell.h
#interface YourCustomCell : UITableViewCell {
IBOutlet UIImageView *theImageView; // make sure you link the outlet properly ;)
}
YourCustomCell.m
- (void)prepareForReuse {
[super prepareForReuse];
theImageView.hidden = YES;
}
And in cellForRow you just have to check if you have notes and make the imageView visible (probably you will make theImageView a property)
Because table view cells are reused you must have a default value for your image. So for example set your image to transparent by default and change it under some condition. This will stop your image being shown in reused cells.
Why do you have a dispatch_async here?
if (!transaction.notes) {
dispatch_async (dispatch_get_main_queue (), ^{
[[customCell viewWithTag:777] removeFromSuperview];
});
}
Because you cannot be sure when the function inside it will execute. Suppose that transaction.notes is nil. All the isEqualToString functions will return false and the else condition of addSubView will be called. But sometime after this function is exited the code inside dispatch_async will be run and remove the pin view. I'm not whether this is the intended behavior.

Resources