reydanro / UIImageViewAligned

A UIImageView subclass which allows you to align the image left/right/top/bottom, even when contentMode is AspectFit.
MIT License
400 stars 69 forks source link

Image is displayed twice whenI switch tabs (UITabBarController) #8

Open guilhermearaujo opened 9 years ago

guilhermearaujo commented 9 years ago

I am using UIImageViewAligned, set to align top, on a custom TabelViewCell. My TableView is contained in a UITabBarController.

If I switch to another tab and return to the table, the image view will redraw the original image, centered.

From what I could debug, the only method called when I switch back to the table tab is - (UIImage*)image { return _realImageView.image; } I couldn't find any solution to that yet.

nickkjordan commented 9 years ago

I'm having a similar issue. It seems to be an issue that sprouted up after updating my app to iOS 8, because it never occurred before

fatuhoku commented 9 years ago

Same here; image is drawn twice. What a shame.

AppsCodeCamp commented 9 years ago

Hey guys, have you been able to fix this bug? Im having the same issue here

esusatyo commented 8 years ago

Same issue here.

AndrewChanChina commented 8 years ago

Same issue here.

mainr commented 7 years ago

Same issue here, but I can provide a bit more detail. In my case, I use the UIImageViewAligned with "AspectFit" mode, and alignTop set to contain a logo image within a UITableView cell. Lets call the currently selected icon "image A". When the cell is selected, it opens another view controller to allow selection of a different icon. Lets say the user selects "image B". On return to the view controller displaying the current logo, the UIImageViewAligned displays "image A" centered, with "image B" overlaid, aligned to top of image. This will of course only be visible if the aspect ratio of both images is such that image B won't completely cover image A.

UIViewAligned is really great, but I need a fix to this issue before I can use it.

UPDATE I'm using PNGs with transparent background. In this case, the aspect ratio is irrelevant - the original image (image A) will be visible behind the new image (image B) - assuming they are not identical. My statement above ("This will or course only be visible...") is not correct.

UPDATE The issue appears to be something to do with view layers (possibly retaining stale info, from the previous display state, possibly to do with animations?) When I return to the original screen, when the "viewDidAppear" executes, the UIImage contains the image it should. At some time later, the image is corrupted. I overloaded the UIImageView function "actionForLayer:forKey:", and logged results.

When my tableview originally loads the sequence is: xyzTVC:viewDidAppear:\ UIImageViewAligned:actionForLayer:forKey: myLay:<CALayer: 0x7be79b70> event:onOrderOut\ UIImageViewAligned:actionForLayer:forKey: myLay:<CALayer: 0x7be79b70> event:onOrderIn\ UIImageViewAligned:actionForLayer:forKey: myLay:<CALayer: 0x7be79b70> event:backgroundColor\ UIImageViewAligned:actionForLayer:forKey: myLay:<CALayer: 0x7be79b70> event:contents\ UIImageViewAligned:actionForLayer:forKey: myLay:<CALayer: 0x7be79b70> event:contents\ UIImageViewAligned:actionForLayer:forKey: myLay:<CALayer: 0x7be79b70> event:contents\ UIImageViewAligned:actionForLayer:forKey: myLay:<CALayer: 0x7be79b70> event:contents\ UIImageViewAligned:actionForLayer:forKey: myLay:<CALayer: 0x7be79b70> event:contents\ UIImageViewAligned:actionForLayer:forKey: myLay:<CALayer: 0x7be79b70> event:contents\ UIImageViewAligned:actionForLayer:forKey: myLay:<CALayer: 0x7be79b70> event:backgroundColor\ UIImageViewAligned:actionForLayer:forKey: myLay:<CALayer: 0x7be79b70> event:contents\ UIImageViewAligned:actionForLayer:forKey: myLay:<CALayer: 0x7be79b70> event:contents\ UIImageViewAligned:actionForLayer:forKey: myLay:<CALayer: 0x7be79b70> event:backgroundColor\ UIImageViewAligned:actionForLayer:forKey: myLay:<CALayer: 0x7be79b70> event:contents\ UIImageViewAligned:actionForLayer:forKey: myLay:<CALayer: 0x7be79b70> event:contents\ UIImageViewAligned:actionForLayer:forKey: myLay:<CALayer: 0x7be79b70> event:contents\ UIImageViewAligned:actionForLayer:forKey: myLay:<CALayer: 0x7be79b70> event:contents\

when the tableview RE-appears (with an updated image), the sequence is: xyzTVC:viewDidAppear:\ UIImageViewAligned:actionForLayer:forKey: myLay:<CALayer: 0x7b885460> event:sublayers\ UIImageViewAligned:actionForLayer:forKey: myLay:<CALayer: 0x7b885460> event:delegate\ UIImageViewAligned:actionForLayer:forKey: myLay:<CALayer: 0x7b88b560> event:sublayers\ UIImageViewAligned:actionForLayer:forKey: myLay:<CALayer: 0x7b88b560> event:delegate\ UIImageViewAligned:actionForLayer:forKey: myLay:<CALayer: 0x7b89ec10> event:sublayers\ UIImageViewAligned:actionForLayer:forKey: myLay:<CALayer: 0x7b89ec10> event:delegate\ UIImageViewAligned:actionForLayer:forKey: myLay:<CALayer: 0x7b8a66f0> event:sublayers\ UIImageViewAligned:actionForLayer:forKey: myLay:<CALayer: 0x7b8a66f0> event:delegate\ UIImageViewAligned:actionForLayer:forKey: myLay:<CALayer: 0x79fb3720> event:sublayers\ UIImageViewAligned:actionForLayer:forKey: myLay:<CALayer: 0x79fb3720> event:delegate\ UIImageViewAligned:actionForLayer:forKey: myLay:<CALayer: 0x79fbea80> event:sublayers\ UIImageViewAligned:actionForLayer:forKey: myLay:<CALayer: 0x79fbea80> event:delegate\ UIImageViewAligned:actionForLayer:forKey: myLay:<CALayer: 0x79e27360> event:sublayers\ UIImageViewAligned:actionForLayer:forKey: myLay:<CALayer: 0x79e27360> event:delegate\

Two things to note:

  1. In first sequence, actionForLayer is invoked many times, but always for the same layer.
  2. In the second sequence, the actionForLayer is invoked many times. Each time, it is inoked for event sublayers and event delegate, and for different layers every other invocation.

I don't have sufficient knowledge to diagnose much further.

mainr commented 7 years ago

FIXED (Well, it worked for me) The issue was with view transitions (segues). In my case, I displayed my "select an logo" view controller with a push segue. I returned to the original view controller by:

[self.navigationController popViewControllerAnimated:YES];

removing the animation from the segue (i.e., popViewControllerAnimated:NO) removed the 'stale image that appeared as background in my UIImageViewAligned view.

It appears animating the display of the view controller with a UIImageViewAligned element that has an updated image will result in a corrupted image. The animation somehow adds stale content to the image.

I hope this helps.

warpling commented 5 years ago

I'm experiencing this inside a view when its ViewController changes size.

accidbright commented 5 years ago

I faced the same issue. Iwas able to fix it by inserting super.image = nil; to the setImage: method:

- (void)setImage:(UIImage *)image
{
    [_realImageView setImage:image];
    super.image = nil;
    [self setNeedsLayout];
}

At least for me now it works

accidbright commented 5 years ago

Unfortunately my previous solution works only on Simulator. Real device still have issue. The workaround I've found is to replace the layer of UIImageViewAligned and set content property always to nil.

  1. Add new class:
    
    @interface ClearImageLayer : CALayer
    @end

@implementation ClearImageLayer

@end


2. Add `layerClass` method to `UIImageViewAligned` class:
  1. (Probably not necessary) Update setImage: method of UIImageViewAligned class:
    - (void)setImage:(UIImage *)image
    {
    [_realImageView setImage:image];
    super.image = nil;
    [self setNeedsLayout];
    }