Closed dreampiggy closed 4 years ago
The idea is similar to what I have in https://github.com/Flipboard/FLAnimatedImage/pull/174 :) Nice writeup!
great!!!
@dreampiggy with #174 I think we don't need to merge this for now? If so I'm going to close this.
@dreampiggy with #174 I think we don't need to merge this for now? If so I'm going to close this.
This can solve 99% use case, but will fail when some case that UIImage is not CGImage based.
🎉
Related Issue
The related issue in FLAnimatedImage repo, it's https://github.com/Flipboard/FLAnimatedImage/issues/181
The related issue in SDWebImage repo, it's https://github.com/rs/SDWebImage/issues/2402 https://github.com/rs/SDWebImage/issues/1317
Reproduce Demo
https://github.com/ericeddy/FLAnimatedImage-RotationIssue
What cause this problem
FLAnimatedImageView
, it's a UIImageView subclass, which manually specify CALayer.contents with the current rendering frame'sCGImage
. And they use a CADisplayLink as a timer, to refresh current frame, finally produce the visual animation.However,
CALayer
itself, contains a private property, calledcontentsTransform
. You can check the private header of CALayer.CALayer
will calculate currentUIImage.imageOrientation
and translate toCGAffineTransform
to render the bitmap. Why they to do this it's because it does not actually take rotation onCGImage
's bitmap when you create UIImage with -[UIImage imageWithCGImage:scale:orientation:], The bothscale
andimageOrientation
are just hint to the CALayer's propertycontentsScale
andcontentsTransform
. So thatCALayer
use thecontentsTransform
to actually do rotation about the bitmap.Which means, actually,
CALayer
draw its contents, based on the both publicCALayer.transform
and privateCALayer.contentsTransform
two properties.See the screenshot during View Debug and print out the CALayer information. The actually
CALayer.contents
bitmap show the correct orientation, but the rendering result cause a rotation because the CALayer contains acontentsTransform = CGAffineTransform (0 1.06667; -0.9375 0; 375 0)
, which is a right-90 degress rotation.After I use KVO to observe this
contentsTransform
changes, I found that the only write on this property was happend on-[UIImageView setImage:]
function call with a non-nilUIImage
. The non-nil is really important, when you sepcify nil, thecontentsTransform
property leave there without reset to identity transform. (Because UIKit assume you don't touch layer.contents and so they don't need to reset the state)So now, you may know the reason now. Correct, the previous JPEG image which contains non-Up image orienation will change the
conrtentsTransform
, but the newly setFLAnimatedImage
does not clear that transform, cause the final rotation. I check the current FLAnimatedImage code and finally find the bug. The root case is that-[FLAnimatedImage setAnimatedImage:]
does not do the correct thing, to reset the superUIImageView
state about image.Solution
The naive solution, it's quite simple, firstlly call
super.image = non-nil image
and then callsuper.image = nil
. Only one line code and the issue disappear.From my personal opinion, I think they should always call
[super setImage:]
during[FLAnimatedImageView setAnimatedImage:]
. If you don't call super, you may loss internal consistent behavior during subclass. But anyway, this fix is much simpler.