Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I customise UIInterpolatingMotionEffect to set different shadow effects based on the device's orientation?

I am using UIInterpolatingMotionEffect to generate a "Shadow Effect" based on device tilt.

I have a label with some text and applying the following code to get the effect:

// Set shadow properties
let layer = self.label.layer
layer.shadowColor = UIColor.blackColor().CGColor
layer.shadowRadius = 9
layer.shadowOpacity = 0.7
layer.shadowOffset = CGSizeMake(10, 10)

// Set vertical shadow effect
let verticalMotionEffect: UIInterpolatingMotionEffect = UIInterpolatingMotionEffect(keyPath: "layer.shadowOffset.height", type: .TiltAlongVerticalAxis)
verticalMotionEffect.minimumRelativeValue = 100
verticalMotionEffect.maximumRelativeValue = -100
    
// Set horizontal shadow effect
let horizontalMotionEffect: UIInterpolatingMotionEffect = UIInterpolatingMotionEffect(keyPath: "layer.shadowOffset.width", type: .TiltAlongHorizontalAxis)
horizontalMotionEffect.minimumRelativeValue = 100
horizontalMotionEffect.maximumRelativeValue = -100
    
// Create group to combine both
let group = UIMotionEffectGroup()
group.motionEffects = [horizontalMotionEffect, verticalMotionEffect]
    
// Add both effects to the label
self.label.addMotionEffect(group)

The result is like this: Screenshot from the device

But I want the text to be invisible when the device is static or when the device is held parallel to the eyes. So one has to rotate / tilt the device to understand what is written.

The font colour is white. In the initial position the shadow should also be white or have 0 opacity and slowly increase the opacity as well as radius based on the device tilt.

I am unable to find a way to capture the device's tilt values, which I can then improvise with conditions to get my desired effect. All my web searches lead me to CMMotionManager. Is there a way to do this through UIInterpolatingMotionEffect or UIMotionEffect?

Thanks in advance!

like image 985
Ashin Mandal Avatar asked Nov 25 '25 13:11

Ashin Mandal


2 Answers

By controlling the layer's shadow opacity, I was able to get the effect I was looking for. I am controlling the shadow opacity through both the tilt axis with a minimum and maximum value of -1.0 and 1.0 since I want the opacity to be 0 initially. Here is the code:

let layer = self.layer
layer.shadowColor = UIColor.blackColor().CGColor
layer.shadowRadius = radius
//layer.shadowOpacity = opacity
layer.shadowOffset = CGSizeMake(offset, offset)

// Set vertical shadow effect
let verticalMotionEffect = UIInterpolatingMotionEffect(keyPath: "layer.shadowOffset.height", type: .TiltAlongVerticalAxis)
verticalMotionEffect.minimumRelativeValue = -parallaxIntensity
verticalMotionEffect.maximumRelativeValue = parallaxIntensity

// Set vertical shadow opacity effect
let verticalTransparencyEffect = UIInterpolatingMotionEffect(keyPath: "layer.shadowOpacity", type: .TiltAlongVerticalAxis)
verticalTransparencyEffect.minimumRelativeValue = -1.0
verticalTransparencyEffect.maximumRelativeValue = 1.0

// Set horizontal shadow effect
let horizontalMotionEffect = UIInterpolatingMotionEffect(keyPath: "layer.shadowOffset.width", type: .TiltAlongHorizontalAxis)
horizontalMotionEffect.minimumRelativeValue = -parallaxIntensity
horizontalMotionEffect.maximumRelativeValue = parallaxIntensity

// Set horizontal shadow opacity effect
let horizontalTransparencyEffect = UIInterpolatingMotionEffect(keyPath: "layer.shadowOpacity", type: .TiltAlongHorizontalAxis)
horizontalTransparencyEffect.minimumRelativeValue = -1.0
horizontalTransparencyEffect.maximumRelativeValue = 1.0

// Create group to combine all effects
let group = UIMotionEffectGroup()
group.motionEffects = [verticalMotionEffect, verticalTransparencyEffect, horizontalMotionEffect, horizontalTransparencyEffect]

// Add both effects to the label
self.addMotionEffect(group)

NOTE: Manual setting of layer.shadowOpacity needs to be disabled for it to work.

like image 106
Ashin Mandal Avatar answered Nov 28 '25 01:11

Ashin Mandal


The idea of the UIInterpolatingMotionEffect is to take care for itself - you just provide the minimum and maximum values and it reads the axis values and translates the tilt value (in the range of -1 to 1) to a value relative to you minimum and maximum ones. It is not intended for directly providing you the tilt value.

A possible "hack", which I do not recommend is to create a transparent view, with min value of -1 and max value of 1. This way you can read the tilt value from this view.

EDIT: You can check this answer Use UIMotionEffect with OpenGL ES which explains a similar approach.

like image 31
o15a3d4l11s2 Avatar answered Nov 28 '25 02:11

o15a3d4l11s2



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!