Effetto parallasse iOS 7 nel controller della vista


112

Sto sviluppando un'app per iOS 7 in Objective-C. Ho uno schermo nella mia app con pochi pulsanti e una bella immagine di sfondo. (È un semplice xib con UIButtonssopra a UIImageView.)

Stavo pensando che sarebbe bello se quei pulsanti avessero l'effetto di parallasse che ha la schermata iniziale di iOS 7, quindi se inclini il telefono potresti vedere lo sfondo.

Come posso implementare quell'effetto nella mia app?


1
Dai

Risposte:


273

Con iOS 7, Apple ha introdotto UIMotionEffectl'aggiunta di effetti di movimento correlati all'orientamento del dispositivo dell'utente. Ad esempio, per emulare l'effetto di parallasse nella schermata iniziale, è possibile utilizzare la sottoclasse UIInterpolationMotionEffect, come spiegato qui e qui , solo con poche righe di codice.

Obiettivo-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 (grazie a @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)

Inoltre, puoi trovare un sacco di librerie per farlo più facilmente o per aggiungere questa funzionalità alle versioni iOS precedenti:


2
NGAParallaxMotion è per iOS 7+, non per le versioni iOS precedenti. Fornisce una categoria per UIView, che consente di impostare un valore .parallaxIntensity, impostando i parametri UIMotionEffect con una riga di codice.
Dan Fabulich

2
Grazie! Ho aggiornato la risposta per includere versioni e requisiti supportati.
veducm

1
In realtà, vuoi aggiungere l'effetto di movimento alla vista di sfondo, non alla vista frontale. Ma a parte questo, questo codice funziona alla grande! Grazie.
gstroup

1
Qualcuno sa come verificare se l'utente ha disabilitato gli effetti? stackoverflow.com/questions/19132000/…
Eric,

3
@gstroup In realtà, nella schermata iniziale sia il primo piano che lo sfondo si muovono. Ma se scegliessi un solo livello a cui applicare l'effetto di parallasse, sono d'accordo che lo sfondo sarebbe probabilmente il migliore.
Rubberduck

16

Tradotto in rapido nel caso qualcuno sia pigro. Per favore, vota la risposta di @veducm se l'hai trovato 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)
}

Grazie @ Lucas! Ho aggiornato la mia risposta per includere anche il campione rapido. È basato su questo. Sentiti libero di esaminarlo e di apportare le modifiche necessarie.
veducm

7

La soluzione di @ veducm può essere un po 'più breve. L'UIMotionEffectGroup per il suo movimento xey è obsoleto se si aggiungono separatamente i motionEffects degli assi xey.

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

2
Proprio come un avvertimento se qualcuno sta usando questa versione abbreviata, il primo effetto di movimento deve avere un typedi UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxise non UIInterpolatingMotionEffectTypeTiltAlongVerticalAxiscome nel codice disposto
Flexicoder

1
@BooHoo Aggiungerli come gruppo è obsoleto? Dove lo vedi? Al momento della stesura di questo documento, i documenti di Apple non hanno nulla sul fatto che sia obsoleto. Lo scopo di raggrupparli è migliorare le prestazioni. Tutti gli effetti nel gruppo vengono renderizzati una volta. Quando li applichi separatamente, devono essere renderizzati separatamente. Sentiti libero di correggermi se sbaglio (e indicami la documentazione di Apple su di esso.)
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];
     }
}

1
@Rob secondo il tuo suggerimento ha aggiornato la risposta
damithH

5

Ecco una semplice categoria per integrare l'effetto su 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


1
Sebbene questo collegamento possa rispondere alla domanda, è meglio includere le parti essenziali della risposta qui e fornire il collegamento come riferimento. Le risposte di solo collegamento possono diventare non valide se la pagina collegata cambia.
Maciej Swic

Sarà difficile integrare l'intero progetto github qui
Bejil

1
Non devi portare l'intero progetto, solo la parte essenziale come ho dimostrato modificando la risposta. Questo è così che il codice rimane in giro nel caso in cui Github sia inattivo, tiri il repo o il cielo cade.
Maciej Swic


3

Questo aiuterà qualcuno che sta cercando di implementare la parallasse per tableView o collectionView.

  • prima di tutto crea la cella per la vista tabella e inserisci la vista immagine al suo interno.

  • imposta l'altezza dell'immagine leggermente superiore all'altezza della cella. se l'altezza della cella = 160 lascia che l'altezza dell'immagine sia 200 (per creare l'effetto di parallasse e puoi cambiarlo di conseguenza)

  • inserire queste due variabili nel viewController o in qualsiasi classe in cui è esteso il delegato tableView

let imageHeight:CGFloat = 150.0
let OffsetSpeed: CGFloat = 25.0
  • aggiungere il codice seguente nella stessa 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))
        }
    }
}
  • dove seriesTabelView è il mio UItableview

  • e ora andiamo alla cella di questo tableView e aggiungiamo il codice seguente

func offset(offset: CGPoint) {
        posterImage.frame = CGRectOffset(self.posterImage.bounds, offset.x, offset.y)
    }
  • erano posterImage è il mio UIImageView

Se vuoi implementarlo in collectionView, cambia semplicemente tableView vairable nella tua variabile collectionView

e questo è tutto. non sono sicuro che questo sia il modo migliore. ma funziona per me. spero che funzioni anche per te. e fammi sapere se c'è qualche problema


2

Davvero facile da fare, perché fa riferimento a codice complesso. provalo e basta. Lavorando

Esamina la visualizzazione dell'immagine con le dimensioni esatte della visualizzazione dell'immagine. per impostazione predefinita alpha per la visualizzazione imposta 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;
}

-1

Traduzione rapida:

// 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)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.