Reimplementing focus tilting animation?

As several people have noted, the standard focus behavior of adjustImageWhenAncestorFocused (or system UIButton) isn't friendly to non-rectangular images.


I'd like to reimplement the focus behavior myself, in a didUpdateFocusInContext:withAnimationCoordinator: routine. (As suggested by many people.) There seem to be four effects here: scale up, drop shadow, tilting, and the gloss reflection.


The scale and drop shadow are easy. I did this:


- (void) didUpdateFocusInContext:(UIFocusUpdateContext *)context withAnimationCoordinator:(UIFocusAnimationCoordinator *)coordinator
{
     if (context.nextFocusedView == self) {
          [coordinator addCoordinatedAnimations:^(){
               self.transform = CGAffineTransformMakeScale(1.1, 1.1);
               self.layer.shadowOpacity = 0.5;
               self.layer.shadowRadius = 32.0;
               self.layer.shadowOffset = CGSizeMake(0, 16);
          } completion:nil];
     }
     if (context.previouslyFocusedView == self) {
          [coordinator addCoordinatedAnimations:^(){
               self.transform = CGAffineTransformIdentity;
               self.layer.shadowOpacity = 0.25;
               self.layer.shadowRadius = 4.0;
               self.layer.shadowOffset = CGSizeZero;
          } completion:nil];
     }
}


But I haven't seen any discussion of the tilting and gloss effects. They're tied to the "wiggle" gesture on the remote, and I'm not sure how to get hold of that data.


(Someone mentioned UIMotionEffect, but that looks like it ties to device orientation rather than a wiggle touch gesture.)


Anyone have sample code?

Hello erkyrath,


I am currently working on a fake tilting for a selection menu that is combined out of different layers. So far a focus only changes the color of the layer (which is okay, but not very appealing). I am currently experimenting with a the translation of a UIPanGestureRecognizer on the layer's view and translating this value to a 3D Transform of the layer. This code should also work for any other view/layer, but it's (of course) very hard to exactly mimic the behaviour of Apple's default tilting. When I get anything close, I will post it here.


I found out that the ImageViews layer.sublayers[0].sublayers[3].sublayers[0] and layer.sublayers[0].sublayers[3].sublayers[1] update their 3D-Transformation and the layer.sublayers[0].sublayers[3] gets a new CIFilter set everytime you pan on a focused element. I don't know if it's possible to reverse engineer the relation between a pan and the corresponding Layer transformation, especially the shadow and the glow/spotlight will be hard. But I'll keep trying

Hi! Any luck faking tilt animations?

I was able to (kind of) replicate the tilting animation for basically any UIView.


The solution is indeed to use UIMotionEffect. In tvOS UIMotionEffect is tied to movements on the siri remote trackpad.


I did it using four different UIInterpolatingMotionEffects in a UIMotionEffectGroup subclass.


    let yRotationMotionEffect = UIInterpolatingMotionEffect(keyPath: "layer.transform", type: .TiltAlongHorizontalAxis)
    let xRotationMotionEffect = UIInterpolatingMotionEffect(keyPath: "layer.transform", type: .TiltAlongVerticalAxis)
    let xMovementMotionEffect = UIInterpolatingMotionEffect(keyPath: "center.x", type: .TiltAlongHorizontalAxis)
    let yMovementMotionEffect = UIInterpolatingMotionEffect(keyPath: "center.y", type: .TiltAlongVerticalAxis)


You can actually leave out the effects for center.x/y. I'm not gonna talk about those any more because they're trivial.


Now here's the issue, we need minimum and maximum relative values for the layer.transform effects. So at first you would think about just applying a CATransform3DRotate() and be good. However, that won't cut it, the view looks very distorted doing that.

Unfortunately I can't explain WHY what's coming up works, but I found it on Stackoverflow (can't find the source atm, will add it if I find it again) in a question about 3D Transforms. It involves manually changing the 3;4 value of the Transform matrix, because that's how you add depth.


Here's an example on how to setup the UIInterpolatingMotionEffect for the view to tilt around the y axis. minMaxAngle is just a parameter (angle in degrees) I pass to the initializer.


        let m34 = CGFloat(1.0 / -1250)
        let angle = CGFloat(minMaxAngle * M_PI / 180.0)
    
        var baseTransform = CATransform3DIdentity
        baseTransform.m34 = m34
    
        var rotateYmin = baseTransform
        rotateYmin = CATransform3DRotate(rotateYmin, angle, 0.0, 1.0, 0.0);
    
        var rotateYmax = baseTransform
        rotateYmax = CATransform3DRotate(rotateYmax, -1 * angle, 0.0, 1.0, 0.0);
    
        yRotationMotionEffect.minimumRelativeValue = NSValue(CATransform3D: rotateYmin)
        yRotationMotionEffect.maximumRelativeValue = NSValue(CATransform3D: rotateYmax)


You can play around with the m34 value, the closer it gets to -1, the more distorted the image gets on movements on the trackpad. Kind of like an intensity value (not exactly though).


I hope I could help.

Reimplementing focus tilting animation?
 
 
Q