Closed gpolyansky closed 6 years ago
I am not familiar with tvOS. Not sure how UIKit works on Apple TV. Should be easy to port if it has core animation and the 'snapshotAfterScreenUpdate' API. Maybe you can put up a PR to contribute to the project.😀
Hey @lkzhao ! I have made a minimal working tvOS example app with Hero from a fork. It's not good enough for me to open a pull request, so you can take a look first here I had to put some conditional compiling in the DebugView because sliders and pinchgestures weren't available in tvOS.
The transition did have a subtle stutter at the beginning, maybe because of the visual effect view, but it could be fixable by tweaking some Hero parameters.
@fruitcoder I have an Apple TV application in production now and in few weeks I will redesign it and make tvOS support for Hero and send PR to @lkzhao if you don't do it faster :)
@fruitcoder I checked out your branch, Looks awesome. It is quite useable already. @f0r3s1 I believe we can get this merged soon, so don't put too much work into this.
@fruitcoder I have just pushed a commit into the master branch that fix the flash that you are seeing. please rebase and let me know if that fixes things.
One thing I have noticed is that the Debug Plugin really doesn't do much in tvOS without the slider. Can we just make the Debug Plugin unavailable in tvOS instead? Later, we can build some gesture to mimic the slider function. But that shouldn't be blocking.
I'll do it right now. Now HeroDebugPlugin
and HeroDebugView
aren't compiled for tvOS
and are, therefore, unavailable.
Your fix works perfectly, the flicker is gone! PR at #71
I updated the master with a some ported examples. Just got myself familiar with tvOS's focus model. One thing I have noticed with ImageView with adjustImageWhenFocused enabled, is that I have no way of snapshotting the focused imageView. Any of you guys know how this can be done?
Do you have a branch that illustrates the issue? What image do you get when snapshotting a focused image view?
@fruitcoder Yes, please checkout the tvOS examples under the imageGallery tab:
The result I got from snapshotting a focused view does not contain the focused effect.
Ah I see! I'll take a look tomorrow
Oh damn... I've had my issues with this super private API of the image view focus behaviour and here we go again. The problem is that the focused image view cannot be snapshotted, because there are CATransformLayer
s involved. See at: https://developer.apple.com/reference/quartzcore/calayer/1410909-render which is used under the hood of snapshotView:afterScreenUpdates
. Comparing layer tree of the cells once with "Adjusts image when focused" and once without shows us:
with focus:
<HeroTvOSExamples.ImageCell: 0x7f8004e18020; baseClass = UICollectionViewCell; frame = (435 64; 307.2 307.2); opaque = NO; layer = <CALayer: 0x6100002245e0>>
| <UIView: 0x7f8004e18440; frame = (0 0; 307.2 307.2); gestureRecognizers = <NSArray: 0x61000005dfa0>; layer = <CALayer: 0x610000224600>>
| | <UIImageView: 0x7f8004e18600; frame = (0 0; 307 307); autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x610000224620>>
| | | <_UIStackedImageContainerView: 0x7f8004e18ce0; frame = (0 0; 307 307); layer = <_UIStackedImageContainerLayer: 0x7f8004e18ea0>>
| | | | <CALayer: 0x610000225080> (layer)
| | | | <CALayer: 0x610000225060> (layer)
| | | | | <CATransformLayer: 0x610000225280> (layer)
| | | | | | <CALayer: 0x610000225400> (layer)
| | | | <CALayer: 0x610000225240> (layer)
| | | | <CALayer: 0x610000225320> (layer)
| | | | | <CATransformLayer: 0x6100002252e0> (layer)
| | | | | | <CATransformLayer: 0x610000225420> (layer)
| | | | | | | <CALayer: 0x610000225300> (layer)
| | | | | | | <CALayer: 0x610000226780> (layer)
| | | | <UIView: 0x7f8004e19340; frame = (0 0; 1 1); layer = <CALayer: 0x610000224f40>>
without focus:
<HeroTvOSExamples.ImageCell: 0x7febc940a020; baseClass = UICollectionViewCell; frame = (64 64; 307.2 307.2); opaque = NO; layer = <CALayer: 0x618000032e80>>
| <UIView: 0x7febc9409d30; frame = (0 0; 307.2 307.2); gestureRecognizers = <NSArray: 0x6180000555d0>; layer = <CALayer: 0x618000032fc0>>
| | <UIImageView: 0x7febc9410910; frame = (0 0; 307 307); autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x618000033320>>
Going deeper on the image view's layer's sublayers:
po (collectionView.cellForItem(at: indexPath) as! ImageCell).imageView.layer.sublayers.first!.sublayers!
â–¿ Optional<Array<CALayer>>
â–¿ some : 5 elements
- 0 : <CALayer:0x608000039f40; position = CGPoint (153.22 153.5); bounds = CGRect (0 0; 505 511); delegate = <_UIStackedImageContainerLayer: 0x7f9dacb114c0>; contents = <CGImage 0x6080001d4a00>
<<CGColorSpace 0x600000028380> (kCGColorSpaceICCBased; kCGColorSpaceModelRGB; sRGB IEC61966-2.1)>
width = 280, height = 280, bpc = 8, bpp = 32, row bytes = 1120
kCGImageAlphaPremultipliedFirst | kCGImageByteOrder32Little
is mask? No, has mask? No, has matte? No, should interpolate? Yes; opacity = 0.5; contentsScale = 1; transform = CATransform3D (1 0 0 0; 0 1 0 0; 0 0 1 0; 0 50 0 1); contentsCenter = CGRect (0.5 0.5; 0 0); shadowColor = <CGColor 0x608000093a60> [<CGColorSpace 0x618000027a40> (kCGColorSpaceICCBased; kCGColorSpaceModelMonochrome; Generic Gray Gamma 2.2 Profile; extended range)] ( 0 1 ); zPosition = -51; animations = [position=<CABasicAnimation: 0x61800002f440>]>
- 1 : <CALayer:0x608000039e20; position = CGPoint (153.5 153.5); bounds = CGRect (0 0; 307 307); delegate = <_UIStackedImageContainerLayer: 0x7f9dacb114c0>; sublayers = (<CATransformLayer: 0x60800003a2e0>); allowsGroupOpacity = YES; >
- 2 : <CALayer:0x60800003a6c0; position = CGPoint (153.314 153.5); bounds = CGRect (0 0; 307 307); contents = <CGImage 0x6080001d4550>
<<CGColorSpace 0x600000028380> (kCGColorSpaceICCBased; kCGColorSpaceModelRGB; sRGB IEC61966-2.1)>
width = 512, height = 512, bpc = 8, bpp = 32, row bytes = 2048
kCGImageAlphaPremultipliedLast | 0 (default byte order)
is mask? No, has mask? No, has matte? No, should interpolate? Yes; hidden = YES; masksToBounds = YES; backgroundColor = (null); animations = [position=<CABasicAnimation: 0x61800003c0e0>]>
- 3 : <CALayer:0x60800003a720; position = CGPoint (153.314 153.5); bounds = CGRect (0 0; 307 307); sublayers = (<CATransformLayer: 0x60800003ab20>); mask = <CATransformLayer: 0x60800003aee0>; filters = (
"<CAFilter: 0x61800005a0d0>"
); animations = [position=<CABasicAnimation: 0x61800002dac0> filters.brightness.inputAmount=<CABasicAnimation: 0x61800002d120>]>
- 4 : <CALayer:0x60800003b420; position = CGPoint (0.5 0.5); bounds = CGRect (0 0; 1 1); delegate = <UIView: 0x7f9dacb133b0; frame = (0 0; 1 1); alpha = 0; layer = <CALayer: 0x60800003b420>>; opaque = YES; allowsGroupOpacity = YES; opacity = 0>
This is the first hint of the visible bounds of the scaled image (CGRect (0 0; 505 511)
), so a super hacky way would be to take that bounds, calculate a transform that would scale the original image to that bounds, and take this as a snapshot for the fromView
. But since internals can change, this would have to be tested for every tvOS release 😔
Oh! I just saw you already got the correct frame via imageView.focusedFrameGuide.layoutFrame
😄
I managed to get the frame correct when coming from a focused view, but I could not yet make it revert to the focused frame because I rely on the cell still being focused: https://github.com/fruitcoder/Hero/tree/tv-os-focus-fix
To make the reverse working I thought about taking the focus from the current view away and forcing the focus back to the previously focused item, but I don't know if that works.
Nice! I feel like this is pretty good already. UIKit refocus the imageView after the dismiss transition with a scale animation. Seems fluid. One thing I have noticed it that white glare suddenly disappears. Is that possible we can focus the imageView we created during the transition to get that glare effect? Or just snapshotting the focused view using resizableSnapshotViewFromRect
I also saw @felix-dumit used a snapshot method with custom bounds when capturing the background for UIVisualEffectView: https://github.com/lkzhao/Hero/issues/26 https://github.com/lkzhao/Hero/commit/7d9f0f11a4c7e94d26fb48f4b0ad25dcd51e10ea
Hm, would be interesting to make that work. The glare seems to be one of the custom layers that don't aren't part of the composition being screenshotted. But maybe if the transition view returns the image view snapshot as its preferredFocusEnvironments
or preferredFocusedView
and calling setNeedsFocusUpdate()
and updateFocusIfNeeded()
on the transition view might produce the glare.
Please, could you add apple tv support