Efecto de paralaje de iOS 7 en mi controlador de vista

112

Estoy desarrollando una aplicación para iOS 7 en Objective-C. Tengo una pantalla en mi aplicación con algunos botones y una bonita imagen de fondo. (Es un xib simple con UIButtonsencima de a UIImageView.)

Estaba pensando que sería genial si esos botones tuvieran el efecto de paralaje que tiene la pantalla de inicio de iOS 7, así que si inclinas el teléfono podrías ver el fondo.

¿Cómo puedo implementar ese efecto en mi propia aplicación?

Dan Fabulich
fuente
1
Eche un vistazo a esta biblioteca: github.com/Przytua/UIView-MWParallax
CRDave
Para más rápido, intente con eso: github.com/ArvindPrakashJoshi/AJParallaxEffect
Arvind

Respuestas:

273

Con iOS 7, Apple introdujo UIMotionEffectpara agregar efectos de movimiento que están relacionados con la orientación del dispositivo del usuario. Por ejemplo, para emular el efecto de paralaje en la pantalla de inicio, puede usar la subclase UIInterpolationMotionEffect, como se explica aquí y aquí , solo con unas pocas líneas de código.

Objetivo-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 (Gracias 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)

Además, puede encontrar un montón de bibliotecas para hacer esto más fácilmente o para agregar esta funcionalidad a versiones anteriores de iOS:

veducm
fuente
2
NGAParallaxMotion es para iOS 7+, no para versiones anteriores de iOS. Proporciona una categoría para UIView, lo que le permite establecer un valor .parallaxIntensity, configurando los parámetros UIMotionEffect con una línea de código.
Dan Fabulich
2
¡Gracias! He actualizado la respuesta para incluir versiones compatibles y requisitos.
veducm
1
En realidad, desea agregar el efecto de movimiento a la vista de fondo, no a la vista frontal. Pero aparte de eso, ¡este código funciona muy bien! Gracias.
gstroup
1
¿Alguien sabe cómo comprobar si el usuario ha desactivado los efectos? stackoverflow.com/questions/19132000/…
Eric
3
@gstroup En realidad, en la pantalla de inicio se mueven tanto el primer plano como el fondo. Pero si tuviera que elegir solo una capa para aplicar el efecto de paralaje, estoy de acuerdo en que el fondo probablemente sería mejor.
Rubberduck
16

Traducido a rápido en caso de que alguien sea vago. Por favor vote @veducm para responder si encuentra esto útil

@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
fuente
¡Gracias @Lucas! He actualizado mi respuesta para incluir también la muestra rápida. Se basa en este. No dude en revisarlo y hacer los cambios necesarios.
veducm
7

La solución de @veducm puede ser un poco más corta. UIMotionEffectGroup para su movimiento xey es obsoleto si agrega los efectos de movimiento de los ejes x e y por separado.

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];
besos y abrazos
fuente
2
Solo como un aviso si alguien está usando esta versión abreviada, el primer efecto de movimiento debe tener un efecto typede UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxisy no UIInterpolatingMotionEffectTypeTiltAlongVerticalAxiscomo está en el código establecido
Flexicoder
1
@BooHoo ¿Agregarlos como grupo es obsoleto? ¿Dónde viste eso? En el momento de escribir este artículo, los documentos de Apple no tienen nada de obsoleto. El propósito de agruparlos es mejorar el rendimiento. Todos los efectos del grupo se renderizan una vez. Cuando los aplica por separado, deben renderizarse por separado. Siéntase libre de corregirme si me equivoco (y señalarme la documentación de Apple al respecto)
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
fuente
1
@Rob de acuerdo con su sugerencia actualizó la respuesta
damithH
5

Aquí hay una categoría fácil para integrar el efecto en 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
fuente
1
Si bien este enlace puede responder a la pregunta, es mejor incluir las partes esenciales de la respuesta aquí y proporcionar el enlace como referencia. Las respuestas de solo enlace pueden dejar de ser válidas si cambia la página enlazada.
Maciej Swic
Será difícil integrar todo el proyecto github aquí
Bejil
1
No tienes que traer todo el proyecto, solo la parte esencial, como demostré al editar la respuesta. Esto es para que el código se mantenga en caso de que Github se caiga, tirar del repositorio o el cielo se caiga.
Maciej Swic
3

Esto ayudará a alguien que esté buscando implementar paralaje para tableView o collectionView.

  • En primer lugar, cree la celda para la vista de tabla y coloque la vista de imagen en ella.

  • establezca la altura de la imagen un poco más que la altura de la celda. si la altura de la celda = 160, deje que la altura de la imagen sea 200 (para hacer el efecto de paralaje y puede cambiarlo en consecuencia)

  • ponga estas dos variables en su viewController o cualquier clase donde su delegado tableView esté extendido

let imageHeight:CGFloat = 150.0
let OffsetSpeed: CGFloat = 25.0
  • agregue el siguiente código en la misma clase
 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))
        }
    }
}
  • donde seriesTabelView es mi UItableview

  • y ahora vayamos a la celda de este tableView y agreguemos el siguiente código

func offset(offset: CGPoint) {
        posterImage.frame = CGRectOffset(self.posterImage.bounds, offset.x, offset.y)
    }
  • eran posterImage es mi UIImageView

Si desea implementar esto en collectionView, simplemente cambie el valor tableView a su variable collectionView

y eso es. No estoy seguro de si esta es la mejor manera. Pero funciona para mí. Espero que funcione para usted también. y avísame si hay algún problema

Muneef M
fuente
2

Realmente fácil de hacer, por eso se refiere a código complejo. solo inténtalo. Trabajando

Observe el tamaño exacto de la vista de la imagen. alfa predeterminado para el conjunto de vistas 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;
}
Señor Javed Multani
fuente
-1

Traducción rápida:

// 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
fuente