Effet de parallaxe iOS 7 dans mon contrôleur de vue

112

Je développe une application pour iOS 7 en Objective-C. J'ai un écran dans mon application avec quelques boutons et une jolie image de fond. (C'est un simple xib avec UIButtonsau dessus d'un UIImageView.)

Je pensais que ce serait cool si ces boutons avaient l'effet de parallaxe de l'écran d'accueil d'iOS 7, donc si vous inclinez le téléphone, vous pouvez voir l'arrière-plan.

Comment puis-je implémenter cet effet dans ma propre application?

Dan Fabulich
la source
1
Jetez un œil à cette bibliothèque: github.com/Przytua/UIView-MWParallax
CRDave
Pour swift, essayez avec ça: github.com/ArvindPrakashJoshi/AJParallaxEffect
Arvind

Réponses:

273

Avec iOS 7, Apple a introduit l' UIMotionEffectajout d'effets de mouvement liés à l'orientation de l'appareil de l'utilisateur. Par exemple, pour émuler l'effet de parallaxe sur l'écran d'accueil, vous pouvez utiliser la sous-classe UIInterpolationMotionEffect, comme expliqué ici et ici , juste avec quelques lignes de code.

Objectif-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 (Merci à @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)

En outre, vous pouvez trouver un tas de bibliothèques pour le faire plus facilement ou pour ajouter cette fonctionnalité aux anciennes versions d'iOS:

veducm
la source
2
NGAParallaxMotion est pour iOS 7+, pas pour les anciennes versions iOS. Il fournit une catégorie pour UIView, vous permettant de définir une valeur .parallaxIntensity, en définissant les paramètres UIMotionEffect avec une ligne de code.
Dan Fabulich le
2
Merci! J'ai mis à jour la réponse pour inclure les versions et les exigences prises en charge.
veducm
1
En fait, vous souhaitez ajouter l'effet de mouvement à la vue d'arrière-plan, pas à la vue de face. Mais à part ça, ce code fonctionne très bien! Merci.
gstroup
1
Est-ce que quelqu'un sait comment vérifier si l'utilisateur a désactivé les effets? stackoverflow.com/questions/19132000/…
Eric
3
@gstroup En fait, sur l'écran d'accueil, le premier plan et l'arrière-plan bougent. Mais si vous deviez choisir un seul calque auquel appliquer l'effet de parallaxe, je conviens que l'arrière-plan serait probablement le meilleur.
Rubberduck
16

Traduit pour rapide au cas où quelqu'un serait paresseux. Veuillez voter @veducm pour répondre si vous avez trouvé cela utile

@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)
}
Lucas
la source
Merci @Lucas! J'ai mis à jour ma réponse pour inclure également l'échantillon rapide. Il est basé sur celui-ci. N'hésitez pas à l'examiner et à apporter les modifications nécessaires.
veducm
7

La solution de @ veducm peut être un peu plus courte. UIMotionEffectGroup pour ses mouvements x et y est obsolète si vous ajoutez séparément les motionEffects des axes x et y.

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];
bisous bisous
la source
2
Tout comme un heads - up si quelqu'un utilise cette version abrégée, les premiers besoins de l' effet de mouvement d'avoir un typede UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxiset non UIInterpolatingMotionEffectTypeTiltAlongVerticalAxiscomme dans le code Disposées
Flexicoder
1
@BooHoo Les ajouter en tant que groupe est obsolète? Où voyez-vous cela? Au moment de la rédaction de cet article, la documentation Apple ne dit rien de son obsolète. Le but de leur regroupement est d'améliorer les performances. Tous les effets du groupe sont rendus une fois. Lorsque vous les appliquez séparément, ils doivent être rendus séparément. N'hésitez pas à me corriger si je me trompe (et indiquez-moi la documentation d'Apple à ce sujet.)
David Lari
6
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];
     }
}
damithH
la source
1
@Rob selon votre suggestion a mis à jour la réponse
damithH
5

Voici une catégorie facile pour intégrer l'effet sur 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

Bejil
la source
1
Bien que ce lien puisse répondre à la question, il est préférable d'inclure les parties essentielles de la réponse ici et de fournir le lien pour référence. Les réponses aux liens uniquement peuvent devenir invalides si la page liée change.
Maciej Swic
Il sera difficile d'intégrer tout le projet github ici
Bejil
1
Vous n'êtes pas obligé d'apporter tout le projet, seulement l'essentiel comme je l'ai démontré en éditant la réponse. C'est pour que le code reste dans le cas où Github est en panne, vous tirez le repo ou le ciel tombe.
Maciej Swic
3

Cela aidera quelqu'un qui cherche à implémenter la parallaxe pour tableView ou collectionView.

  • tout d'abord, créez la cellule de la vue table et placez-y la vue image.

  • définissez la hauteur de l'image légèrement plus que la hauteur de la cellule. si la hauteur de la cellule = 160 laissez la hauteur de l'image être de 200 (pour créer l'effet de parallaxe et vous pouvez la modifier en conséquence)

  • mettez ces deux variables dans votre viewController ou dans n'importe quelle classe où votre délégué tableView est étendu

let imageHeight:CGFloat = 150.0
let OffsetSpeed: CGFloat = 25.0
  • ajoutez le code suivant dans la même classe
 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))
        }
    }
}
  • où seriesTabelView est mon UItableview

  • et maintenant allons à la cellule de cette tableView et ajoutons le code suivant

func offset(offset: CGPoint) {
        posterImage.frame = CGRectOffset(self.posterImage.bounds, offset.x, offset.y)
    }
  • étaient posterImage est mon UIImageView

Si vous souhaitez implémenter cela dans collectionView, changez simplement le vairable tableView en votre variable collectionView

et c'est tout. je ne sais pas si c'est la meilleure façon. Mais cela fonctionne pour moi. J'espère que ça marchera pour toi aussi. et faites-moi savoir s'il y a un problème

Muneef M
la source
2

Vraiment facile à faire, pourquoi se réfère à un code complexe. essayez-le.Travail

Prenez une vue sur imageview exactement la taille de vue d'image. par défaut alpha pour l'ensemble de vues 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;
}
Monsieur Javed Multani
la source
-1

Traduction Swift:

// 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)
mukaissi
la source