视图控制器中的 iOS7视差效应

我在 Objective-C 中为 iOS 7开发一个应用程序。我的应用程序中有一个屏幕,上面有几个按钮和一张漂亮的背景图片。(它是一个简单的 xib,UIButtonsUIImageView上。)

我在想如果这些按钮有 iOS7主屏幕的视差效果会很酷,所以如果你倾斜手机,你可以看到背景。

我如何在自己的应用程序中实现这种效果?

64476 次浏览

UIMotionEffect provides a free parallax implementation on iOS 7.

http://www.teehanlax.com/blog/introduction-to-uimotioneffect/

https://github.com/michaeljbishop/NGAParallaxMotion lets you just set the parallax intensity.

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:

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

https://github.com/jvenegas/TLMotionEffect

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];
}
}

@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];

Swift translation:

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


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


let group = UIMotionEffectGroup()
group.motionEffects = [horizontalMotionEffect, verticalMotionEffect]
self.motionEffect = group
self.addMotionEffect(group)

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)
}

This will help someone who is looking to implement parallax for tableView or collectionView.

  • first of all create the cell for the tableview and put the image view in it.

  • set the image height slightly more than the cell height. if cell height = 160 let the image height be 200 (to make the parallax effect and you can change it accordingly)

  • put this two variable in your viewController or any class where your tableView delegate is extended

let imageHeight:CGFloat = 150.0
let OffsetSpeed: CGFloat = 25.0
  • add the following code in the same class
 func scrollViewDidScroll(scrollView: UIScrollView) {
//  print("inside scroll")


if let visibleCells = seriesTabelView.visibleCells as? [SeriesTableViewCell] {
for parallaxCell in visibleCells {
var yOffset = ((seriesTabelView.contentOffset.y - parallaxCell.frame.origin.y) / imageHeight) * OffsetSpeedTwo
parallaxCell.offset(CGPointMake(0.0, yOffset))
}
}
}
  • where seriesTabelView is my UItableview

  • and now lets goto the cell of this tableView and add the following code

func offset(offset: CGPoint) {
posterImage.frame = CGRectOffset(self.posterImage.bounds, offset.x, offset.y)
}
  • were posterImage is my UIImageView

If you want to implement this to collectionView just change the tableView vairable to your collectionView variable

and thats it. i am not sure if this is the best way. but it works for me. hope it works for you too. and let me know if there is any problem

Really dam easy to do so why refers complex code. just try it. Working

Take a view on imageview exactly size of image view. by default alpha for view set 0.

//MARK: Scroll View Delegate methods
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{


NSLog(@"X: %f Y: %f",scrollView.contentOffset.x,scrollView.contentOffset.y);


CGFloat scrollY = _mainScrollView.contentOffset.y;
CGFloat height = _alphaView.frame.size.height;


CGFloat alphaMonitor = scrollY/height;


_alphaView.alpha = alphaMonitor;
}