tvOS: Rounded corners for image view when focused
Asked Answered
A

3

7

I have an image view that will get this awesome tvOS focus effect when the containing view gets focused. The problem is - it should have rounded corners. Now this is easily done:

imageView.layer.cornerRadius = 5
imageView.layer.masksToBounds = true 

I have to set either masksToBounds of the layer or clipsToBounds of the image view to true (which is basically the same), in order to clip the edges of the image - but as soon as I do this, the focus effect won't work any more, because it will get clipped as well.

I had more or less the same problem with buttons, but since the focus effect is much simpler than for the image view (only scaling and shadow), I just implemented it myself, but that is not an option for the image view, with all the effects applied (moving, shimmering, and so on...)

Is there an easier way? Did I miss something? I can't be the only trying to figure out how this works!? :)

Adjure answered 14/12, 2015 at 23:5 Comment(1)
A decade later, the easy way is just use UICardView on tvOS.Whizbang
S
6

I have found out an alternative solution. What one may do is to actually draw the image, clipping out the corners with an alpha channel. The image then gets scaled correctly when focused. That applied to the layer. Then, to have the alpha channel added to the other layers (like the one for the glowing effect) we need to set; "masksFocusEffectToContents = true".

I made an extension for it, based on this answer:

Swift 4.2

extension UIImageView {
func roundedImage(corners: UIRectCorner, radius: CGFloat)  {
        let rect = CGRect(origin:CGPoint(x: 0, y: 0), size: self.frame.size)
        UIGraphicsBeginImageContextWithOptions(self.frame.size, false, 1)
        UIBezierPath(
            roundedRect: rect,
            byRoundingCorners: corners,
            cornerRadii: CGSize(width: radius, height: radius)
            ).addClip()
        self.draw(rect)
        self.image = UIGraphicsGetImageFromCurrentImageContext()!

        // Shadows - Change shadowOpacity to value > 0 to enable the shadows
        self.layer.shadowOpacity = 0
        self.layer.shadowColor = UIColor.black.cgColor
        self.layer.shadowOffset = CGSize(width: 10, height: 15)
        self.layer.shadowRadius = 3

        // This propagate the transparency to the the overlay layers, 
        // like the one for the glowing effect. 
        self.masksFocusEffectToContents = true
    }
}

Then to apply the rounded corners call:

myImageView.adjustsImageWhenAncestorFocused = true
myImageView.clipToBounds = false

// masks all corners with a radius of 25 in myImageView
myImageView.roundedImage(corners: UIRectCorner.allCorners, radius: 25)

One can obviously modify roundedImage() to add the parameters to define the shadows at the calling time.

Downsides:

  • Borders behave like cornerRadius (they get drawn inside the image). But I think I made it working somewhere, then investigating further I lost the changes
  • I am not exactly sure this is the right way to do it. I am quite confident there must be some methods out there doing it in a couple of lines. In tvOS 11 Apple introduced the round badges (animatable and all), shown at WWDC 2017. I just can't find a sample for them.

Otherwise, tvOS 12 (beta for now) introduced the Lockup. I managed to implement them programmatically, as shown in this answer.

Subheading answered 2/8, 2018 at 10:50 Comment(1)
it's really unfortunate to have to render every image like this!Whizbang
M
3

https://forums.developer.apple.com/thread/20513

We are also facing this same issue. When you round the corners, you can see the "shine" still has a rectange shape.

I showed the issue to the Dev Evangelists at the Tech Talks in Toronto and they said it's a bug. It's reported and open rdar://23846376

Modification answered 11/3, 2016 at 13:26 Comment(1)
Was that fixed eventually? Because I am still getting the same issue with Xcode 10 beta 3 on tvOS 12 beta and I have lost 3 days already trying to find a solution.Dian
W
0

For 2022 2023 ...

import TVUIKit to use TVPosterView.

Fortunately TVPosterView now works pretty well. It's likely your best solution. Just set .image on the TVPosterView`.

You can also just use UICardView for the effect. (In that case simply put the UIImageView inside the card view. Don't forget to actually turn OFF "adjust on ancestor focus" and "user interaction enabled" on the image view, or else it will "doubly expand" when the card view expands!)

  • with TVPosterView you get "both" of the 3D effects when toying the remote.

  • with UICardView it's different, you only get "one" of the 3D effects when toying the remote. Try it, to see the difference.

However ...

  • with TVPosterView you do suffer the strange problem (as with just an image view) that the image simply won't scale properly, it ignores the scaling mode.

  • with UICardView the image will scale normally (however you tell it to) just as on iOS

Whizbang answered 3/10, 2022 at 12:36 Comment(2)
This is the correct approach, imo. In case it's not clear, TVPosterView is a class created by Apple and available in TVUIKit for handling this exact situation. It's flexible enough that it should work great for most people's needs. developer.apple.com/documentation/tvuikit/tvposterviewCatenane
great point @AdamKaump . the only snag that remains is the incredibly weird problem that, it just won't scale an image. your images have to come from your content server "at the exact size", which is absurd. it's like the biggest probloem in tvOS !Whizbang

© 2022 - 2024 — McMap. All rights reserved.