iOS 7 parallax effect in my view controller
Solution 1
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).
Solution 2
Translated to swift in case anyone is lazy. Please vote @veducm answer up if you found this useful
@IBOutlet var background : UIImageView!
func parallaxEffectOnBackground() {
let relativeMotionValue = 50
var verticalMotionEffect : UIInterpolatingMotionEffect = UIInterpolatingMotionEffect(keyPath: "center.y",
type: .TiltAlongVerticalAxis)
verticalMotionEffect.minimumRelativeValue = -relativeMotionValue
verticalMotionEffect.maximumRelativeValue = relativeMotionValue
var horizontalMotionEffect : UIInterpolatingMotionEffect = UIInterpolatingMotionEffect(keyPath: "center.x",
type: .TiltAlongHorizontalAxis)
horizontalMotionEffect.minimumRelativeValue = -relativeMotionValue
horizontalMotionEffect.maximumRelativeValue = relativeMotionValue
var group : UIMotionEffectGroup = UIMotionEffectGroup()
group.motionEffects = [horizontalMotionEffect, verticalMotionEffect]
self.background.addMotionEffect(group)
}
Solution 3
@veducm's solution can be a little shorter. The UIMotionEffectGroup for its x and y motion is obsolete if you add the the x and y-axis motionEffects separately.
UIInterpolatingMotionEffect *motionEffect;
motionEffect = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.x"
type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
motionEffect.minimumRelativeValue = @(-25);
motionEffect.maximumRelativeValue = @(25);
[bgView addMotionEffect:motionEffect];
motionEffect = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.y"
type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
motionEffect.minimumRelativeValue = @(-25);
motionEffect.maximumRelativeValue = @(25);
[bgView addMotionEffect:motionEffect];
Solution 4
const static CGFloat kCustomIOS7MotionEffectExtent = 10.0;
- (void)applyMotionEffects:(UIView *YOUR_VIEW) {
if (NSClassFromString(@"UIInterpolatingMotionEffect")) {
UIInterpolatingMotionEffect *horizontalEffect = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.x"
type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
horizontalEffect.minimumRelativeValue = @(-kCustomIOS7MotionEffectExtent);
horizontalEffect.maximumRelativeValue = @( kCustomIOS7MotionEffectExtent);
UIInterpolatingMotionEffect *verticalEffect = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.y"
type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
verticalEffect.minimumRelativeValue = @(-kCustomIOS7MotionEffectExtent);
verticalEffect.maximumRelativeValue = @( kCustomIOS7MotionEffectExtent);
UIMotionEffectGroup *motionEffectGroup = [[UIMotionEffectGroup alloc] init];
motionEffectGroup.motionEffects = @[horizontalEffect, verticalEffect];
[YOUR_VIEW addMotionEffect:motionEffectGroup];
}
}
Solution 5
Here is an easy category to integrate the effect on iOs7+ :
NSString *const centerX = @"center.x";
NSString *const centerY = @"center.y";
//#define IS_OS_7_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0)
@implementation UIView (TLMotionEffect)
- (void)addCenterMotionEffectsXYWithOffset:(CGFloat)offset {
// if(!IS_OS_7_OR_LATER) return;
if(floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1) return;
UIInterpolatingMotionEffect *xAxis;
UIInterpolatingMotionEffect *yAxis;
xAxis = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:centerX type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
xAxis.maximumRelativeValue = @(offset);
xAxis.minimumRelativeValue = @(-offset);
yAxis = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:centerY type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
yAxis.minimumRelativeValue = @(-offset);
yAxis.maximumRelativeValue = @(offset);
UIMotionEffectGroup *group = [[UIMotionEffectGroup alloc] init];
group.motionEffects = @[xAxis, yAxis];
[self addMotionEffect:group];
}
@end
Related videos on Youtube
Dan Fabulich
Updated on October 10, 2020Comments
-
Dan Fabulich over 3 years
I'm developing an app for iOS 7 in Objective-C. I've got a screen in my app with a few buttons and a pretty background image. (It's a simple xib with
UIButtons
on top of aUIImageView
.)I was thinking that it'd be cool if those buttons had the parallax effect that the iOS 7 home screen has, so if you tilt the phone you could see the background.
How can I implement that effect in my own app?
-
CRDave over 10 yearsHave a look at this library : github.com/Przytua/UIView-MWParallax
-
Arvind almost 9 yearsFor swift, try with that: github.com/ArvindPrakashJoshi/AJParallaxEffect
-
-
Dan Fabulich over 10 yearsNGAParallaxMotion is for iOS 7+, not for older iOS versions. It provides a category for UIView, allowing you to set a .parallaxIntensity value, setting up the UIMotionEffect parameters with one line of code.
-
veducm over 10 yearsThanks! I have updated the answer to include supported versions and requirements.
-
gstroup over 10 yearsActually, you want to add the motion effect to the background view, not the front view. But other than that, this code works great! Thanks.
-
veducm over 10 yearsThanks @gstroup! I have updated the code to be 'myBackgroundView'.
-
Eric over 10 yearsDoes anyone know how to check if the user has disabled the effects? stackoverflow.com/questions/19132000/…
-
Rubberduck over 10 years@gstroup Actually, on the home screen both the foreground and the background are moving. But if you were to chose only one layer to apply the parallax effect to, I agree the background would probably be best.
-
dcone almost 10 years@veducm: What about a parallax pinch zoom effect, how will this be done?
-
veducm almost 10 years@dcone: not sure this is what you are looking for. Otherwise, could you please give an example to understand what you want?
-
Flexicoder almost 10 yearsJust as a heads up if anyone is using this shortened version, the first motion effect needs to have a
type
ofUIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis
and notUIInterpolatingMotionEffectTypeTiltAlongVerticalAxis
as it is in the code laid out -
damithH over 9 years@Rob according to your suggestion updated the answer
-
Maciej Swic over 9 yearsWhile this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes.
-
Bejil over 9 yearsIt will be hard to integrate the whole github project here
-
Maciej Swic over 9 yearsYou don't have to bring the whole project, only the essential part like i demonstrated by editing the answer. This is so that the code sticks around in case Github is down, you pull the repo or the sky falls down.
-
veducm over 9 yearsThanks @Lucas! I have updated my answer to include the swift sample too. It is based on this one. Feel free to review it and do any changes needed.
-
Daniel Saidi over 9 yearsThis worked right away, in a way that was exactly what I was after. Thank you so much!
-
Ryan about 9 yearsAn important configuration that is necessary to think about for anyone using parallax, is that you need to consider the Z-axis layering of the view. If the view is to look "above", you will have a minimumRelativeValue less than the maximumRelativeValue. If the view is to look "behind" (such as iOS home/lock screen), then the values are to be reversed.
-
GilesDMiddleton about 9 yearsAny ideas how to apply this so it just moves a single sprite kit SKSpriteNode inside an SKScene, rather than a whole view moving?
-
David Lari about 8 years@BooHoo Adding them as a group is obsolete? Where do you see that? As of the time of this writing the Apple docs don't have anything about it being obsolete. The whole purpose of grouping them is to improve performance. All effects in the group are rendered once. When you apply them separately, they must be rendered separately. Feel free to correct me if I'm wrong (and point me to Apple's documentation on it.)