How to make a UIImageView focusable using the focus engine on Apple TV

2.1k Views Asked by At

Is it possible to make a UIImageView focusable? Or should I just use a UICollectionView for all possible views?

I tried to override canBecomeFocused but nothing happened.

2

There are 2 best solutions below

0
On

Try wrapping the UIImageView in a container view, making the container view focusable, and using:

imageView.adjustsImageWhenAncestorFocused = true
imageView.clipsToBounds = false

This should give you several focus effects at once:

  • scale up
  • drop shadow
  • 2D parallax on panning
  • And last but not least: light shimmer effect on panning

If you want to implement your own UIImageView focus effect instead, you can do what you did (override canBecomeFocused = true) but also add:

    override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {
        coordinator.addCoordinatedAnimations({
           self.transform = self.isFocused ? CGAffineTransform( scaleX:1.1, y:1.1 ) : .identity
        }, completion: nil)
    }

Just know that the adjustsImageWhenAncestorFocused option is all or nothing. So you can either take all four system focus effects exactly as they are or lose all four of them and implement all focus effects yourself. Because the shimmer effect is impossible to recreate for all practical purposes, it is usually best to stick with adjustsImageWhenAncestorFocused.

0
On

The easiest way I found was to subclass UIButton instead of UIImageView (since UIButton already has an image subview). You may not need all I put in there (the important part is setting imageView?.adjustsImageWhenAncestorFocused = true in layoutSubviews)

class AtvImageButton:UIButton
{

   override func awakeFromNib() 
   {
      super.awakeFromNib()      
      contentMode = UIViewContentMode.ScaleAspectFit
      contentHorizontalAlignment = .Fill 
      contentVerticalAlignment   = .Fill     
   }

   override func layoutSubviews() 
   {
      imageView?.adjustsImageWhenAncestorFocused = true
      imageView?.clipsToBounds = false  
      super.layoutSubviews()
   }

   override func canBecomeFocused() -> Bool
   {
      return enabled && super.canBecomeFocused()
   }

}