iOS 7 Parallax Effect in My View Controller

iOS 7 parallax effect in my view controller

With iOS 7, Apple introduced UIMotionEffect to add Motion effects that are related to the orientation of the user’s device. For example, to emulate the parallax effect on the home screen, you can use the subclass UIInterpolatingMotionEffect, as explained here, just with a few lines of code.

Objective-C:

// Set vertical effect
UIInterpolatingMotionEffect *verticalMotionEffect =
[[UIInterpolatingMotionEffect alloc]
initWithKeyPath:@"center.y"
type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
verticalMotionEffect.minimumRelativeValue = @(-10);
verticalMotionEffect.maximumRelativeValue = @(10);

// Set horizontal effect
UIInterpolatingMotionEffect *horizontalMotionEffect =
[[UIInterpolatingMotionEffect alloc]
initWithKeyPath:@"center.x"
type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
horizontalMotionEffect.minimumRelativeValue = @(-10);
horizontalMotionEffect.maximumRelativeValue = @(10);

// Create group to combine both
UIMotionEffectGroup *group = [UIMotionEffectGroup new];
group.motionEffects = @[horizontalMotionEffect, verticalMotionEffect];

// Add both effects to your view
[myBackgroundView addMotionEffect:group];

Swift (Thanks to @Lucas):

// Set vertical effect
let verticalMotionEffect = UIInterpolatingMotionEffect(keyPath: "center.y",
type: .TiltAlongVerticalAxis)
verticalMotionEffect.minimumRelativeValue = -10
verticalMotionEffect.maximumRelativeValue = 10

// Set horizontal effect
let horizontalMotionEffect = UIInterpolatingMotionEffect(keyPath: "center.x",
type: .TiltAlongHorizontalAxis)
horizontalMotionEffect.minimumRelativeValue = -10
horizontalMotionEffect.maximumRelativeValue = 10

// Create group to combine both
let group = UIMotionEffectGroup()
group.motionEffects = [horizontalMotionEffect, verticalMotionEffect]

// Add both effects to your view
myBackgroundView.addMotionEffect(group)

Also, you can find a bunch of libraries to do this easier or to add this functionality to older iOS versions:

  • NGAParallaxMotion (requires iOS 7).
  • DVParallaxView (requires iOS 5.0 or higher and ARC).
  • MKParallaxView (tested with iOS 6.0, requires ARC).
  • UIView-MWParallax (tested with iOS 6.1, requires ARC).

xcode/ios7: parallax effect with image clipped inside view

I think a better approach here might just be to use 2 separate views.

  1. The wrapping UIView you have now, sized to what you want with a corner radius and clipsToBounds set to YES.
  2. a UIImageView with the image you want, added as a subview of the UIView.

Then, just apply the motion effect to the image view. This will keep the containing view static and achieve the keyhole effect you are looking for.

Moving an image with ios 7 parallax effect

Update:
Just found a very nice 3rd party library for achieving this, it's called CRMotionView, it works very smooth and you can modify a lot of things.

here is the github link: https://github.com/chroman/CRMotionView

==================================================================================

i was thinking the same parallax when i first saw Facebook paper app. but after play with my code for a little bit, i don't think parallax is what we looking for. I could be wrong, but i went to do it all from the base, gyro motion manager. Here is my sample code:

     //import the motion manager frame work first
#import <CoreMotion/CoreMotion.h>

//then need to add a motionManager
@property (strong, nonatomic) CMMotionManager *motionManager;

//you can paste all those codes in view did load
//i added a scroll view on the view controller nib file
self.mainScrollView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
//we don't want it to bounce at each end of the image
self.mainScrollView.bounces = NO;

//and we don't want to allow user scrolling in this case
self.mainScrollView.userInteractionEnabled = NO;

//set up the image view
UIImage *image= [UIImage imageNamed:@"YOUR_IMAGE_NAME"];
UIImageView *movingImageView = [[UIImageView alloc]initWithImage:image];
[self.mainScrollView addSubview:movingImageView];

//set up the content size based on the image size
//in facebook paper case, vertical rotation doesn't do anything
//so we dont have to set up the content size height
self.mainScrollView.contentSize = CGSizeMake(movingImageView.frame.size.width, self.mainScrollView.frame.size.height);

//center the image at intial
self.mainScrollView.contentOffset = CGPointMake((self.mainScrollView.contentSize.width - self.view.frame.size.width) / 2, 0);

//inital the motionManager and detec the Gyroscrope for every 1/60 second
//the interval may not need to be that fast
self.motionManager = [[CMMotionManager alloc] init];
self.motionManager.gyroUpdateInterval = 1/60;

//this is how fast the image should move when rotate the device, the larger the number, the less the roation required.
CGFloat motionMovingRate = 4;

//get the max and min offset x value
int maxXOffset = self.mainScrollView.contentSize.width - self.mainScrollView.frame.size.width;
int minXOffset = 0;

[self.motionManager startGyroUpdatesToQueue:[NSOperationQueue currentQueue]
withHandler:^(CMGyroData *gyroData, NSError *error) {
//since our hands are not prefectly steady
//so it will always have small rotation rate between 0.01 - 0.05
//i am ignoring if the rotation rate is less then 0.1
//if you want this to be more sensitive, lower the value here
if (fabs(gyroData.rotationRate.y) >= 0.1) {
CGFloat targetX = self.mainScrollView.contentOffset.x - gyroData.rotationRate.y * motionMovingRate;
//check if the target x is less than min or larger than max
//if do, use min or max
if(targetX > maxXOffset)
targetX = maxXOffset;
else if (targetX < minXOffset)
targetX = minXOffset;

//set up the content off
self.mainScrollView.contentOffset = CGPointMake(targetX, 0);
}
}];

I tested this on my device, worked pretty similar like facebook new app.

However, this is just an example code i wrote in half hour, may not be 100% accurate, but hope this would give you some ideas.

Parallax effect with UIMotionEffect not working

In the code that you have shared, one thing that I noticed is that you are using capital T in the enums .TiltAlongHorizontalAxis and .TiltAlongVerticalAxis, which don't compile (at least on Xcode 11.4.1) -> those need to be changed to lowercase T.

Apple's documentation for those enums is here.

Other than that, I don't see any problems with the code that you shared. In fact I created a sample project with a simple imageView in the view to which I added constraints so that it fills up the entire space of its superview.

I then added the motion effects code that you shared, and ran it on an actual device (iPad Pro). It worked perfectly.

Could you check a few things that might be a source of the problem:

  • Double check that Settings > Accessibility > Motion > Reduce Motion is not turned on. Because if it is turned on, then UIInterpolatingMotionEffect won't work.
  • Test that the accelerometer of the device that you are testing on actually works. Or better still, use another device to test it. (This won't work on the simulator).
  • If you are editing the frame of the imageView in code anywhere (or especially in viewWillLayout / viewDidLayout), you shouldn't be doing that.

In any case, if none of these things help you to fix your problem, can you create a simple sample project which demonstrates the bug and post it on Github? I can try to help if I can actually reproduce the problem.



Related Topics



Leave a reply



Submit