UIMotionEffect Not Working in iOS 14?

I'm trying to get a parallax effect similar to the home screen background. I've seen numerous examples of this working with a UIInterpolatingMotionEffect but I cannot get it to work on my iOS 14 devices (I've confirmed that the reduce motion setting is NOT enabled and the home screen background is moving like normal, so I know it works on my device).

I've tried variations of this code, adding it to a view / button / label and nothing happens... any ideas? Thank you!

Code Block        
let horizontal = UIInterpolatingMotionEffect(keyPath: "center.x", type: .tiltAlongHorizontalAxis)
horizontal.minimumRelativeValue = -50
horizontal.maximumRelativeValue = 50
let vertical = UIInterpolatingMotionEffect(keyPath: "center.x", type: .tiltAlongVerticalAxis)
vertical.minimumRelativeValue = -50
vertical.maximumRelativeValue = 50
let group = UIMotionEffectGroup()
group.motionEffects = [horizontal, vertical]
label.addMotionEffect(group)


Accepted Reply

I don't know, is it a bug, or some new mega-features:)
If you call addMotionEffect in init or other method before your view really appeared at the screen - it doesn't work. But if you do it when your view is at the screen - its OK!!!

Here's my working solution:

override func didMoveToWindow() {
    super.didMoveToWindow()
    guard window != nil else {
      pictureView.removeMotionEffect(pictureParralaxEffect)
      return
    }
    pictureView.addMotionEffect(pictureParralaxEffect)
  }

(Sorry for my awful English))))

Replies

Yes, UIMotionEffect is completely broken in iOS 14. I filed a bug report early on (FB8039897), but no reply or fix so far.

Do file another bug report, the more bug reports Apple gets about it, the more likely it is they are going to fix it.

Post not yet marked as solved Up vote reply of ppix Down vote reply of ppix
Ah that's actually good news. I was pulling my hair out trying to figure out what I was doing wrong. I suspected it was an iOS 14 bug but didn't have any iOS 13 devices to compare... I will file another bug report. Thank you.
I filed FB8369431 for this bug too.

I noticed that the problem is that the motion effect can't be added to the view. Immediately after adding it you can see that view.motionEffects is still empty.

I haven't had time to do this, but it might help to use Hopper Dissasembler to look at the addMotionEffect implementation. Maybe there is a permission check we are failing, such as a new undocumented requirement to access the accelerometer data?

Here is the very easy repro:
Code Block
let effect = UIInterpolatingMotionEffect(keyPath: "center.x",type: .tiltAlongHorizontalAxis)
effect.minimumRelativeValue = -10
effect.maximumRelativeValue = 10
blueView.addMotionEffect(effect)
if blueView.motionEffects.count == 0 {
print("Oh no! Why didn't the effect get added? :'( ")
}
It looks like UIMotionEffect still works on the Springboard, if that is what they use for the effect there.
I did ultimately file a bug report as well.

Good insights, @bridger. Originally two things made me think it wasn't an iOS 14 bug: 1) it works on springboard as you mentioned and 2) this guy's sample project does work on iOS 14 out of the box https://github.com/NachoMan/Example-UIMotionEffect but his use was so complex that I couldn't easily reverse engineer what he was doing.
I don't know, is it a bug, or some new mega-features:)
If you call addMotionEffect in init or other method before your view really appeared at the screen - it doesn't work. But if you do it when your view is at the screen - its OK!!!

Here's my working solution:

override func didMoveToWindow() {
    super.didMoveToWindow()
    guard window != nil else {
      pictureView.removeMotionEffect(pictureParralaxEffect)
      return
    }
    pictureView.addMotionEffect(pictureParralaxEffect)
  }

(Sorry for my awful English))))
danil_la - Woah, you're right. If you put the motion code into viewDidAppear it works as expected, but viewDidLoad does not. Good catch! Thank you!
Do you know if they ever got around to fixing this?