Efeito de paralaxe do iOS 7 em meu controlador de visualização


112

Estou desenvolvendo um aplicativo para iOS 7 em Objective-C. Eu tenho uma tela no meu aplicativo com alguns botões e uma bela imagem de fundo. (É um xib simples com UIButtonsem cima de um UIImageView.)

Eu estava pensando que seria legal se esses botões tivessem o efeito de paralaxe que a tela inicial do iOS 7 tem, então se você inclinar o telefone você pode ver o fundo.

Como posso implementar esse efeito em meu próprio aplicativo?


1
Dê uma olhada nesta biblioteca: github.com/Przytua/UIView-MWParallax
— CRDave

Respostas:


273

Com o iOS 7, a Apple introduziu UIMotionEffecta adição de efeitos de movimento relacionados à orientação do dispositivo do usuário. Por exemplo, para emular o efeito de paralaxe na tela inicial, você pode usar a subclasse UIInterpolationMotionEffect, conforme explicado aqui e aqui , apenas com algumas linhas de código.

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 (graças 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)

Além disso, você pode encontrar várias bibliotecas para fazer isso mais facilmente ou para adicionar essa funcionalidade a versões mais antigas do iOS:


2
NGAParallaxMotion é para iOS 7 ou superior, não para versões mais antigas do iOS. Ele fornece uma categoria para UIView, permitindo que você defina um valor .parallaxIntensity, configurando os parâmetros UIMotionEffect com uma linha de código.
— Dan Fabulich

2
Obrigado! Eu atualizei a resposta para incluir versões e requisitos com suporte.
— veducm 01 de

1
Na verdade, você deseja adicionar o efeito de movimento à vista de fundo, não à vista frontal. Mas fora isso, este código funciona muito bem! Obrigado.
— gstroup

1
Alguém sabe verificar se o usuário desabilitou os efeitos? stackoverflow.com/questions/19132000/…
— Eric

3
@gstroup Na verdade, na tela inicial tanto o primeiro quanto o segundo plano estão se movendo. Mas se você escolhesse apenas uma camada para aplicar o efeito de paralaxe, concordo que o plano de fundo provavelmente seria o melhor.
— Rubberduck

16

Traduzido para rápido no caso de alguém ser preguiçoso. Vote na resposta @veducm se você achou isso ú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)
}

Obrigado @Lucas! Eu atualizei minha resposta para incluir a amostra rápida também. É baseado neste. Sinta-se à vontade para revisá-lo e fazer as alterações necessárias.
— veducm

7

A solução de @ veducm pode ser um pouco mais curta. O UIMotionEffectGroup para seu movimento xey torna-se obsoleto se você adicionar os efeitos de movimento dos eixos xey separadamente.

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
Apenas como um alerta, se alguém estiver usando esta versão abreviada, o primeiro efeito de movimento precisa ter um typede UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxise não UIInterpolatingMotionEffectTypeTiltAlongVerticalAxiscomo está no código apresentado
— Flexicoder

1
@BooHoo Adicioná-los como um grupo é obsoleto? Onde você vê isso? No momento em que este livro foi escrito, os documentos da Apple não tinham nada sobre isso ser obsoleto. O objetivo de agrupá-los é melhorar o desempenho. Todos os efeitos no grupo são renderizados uma vez. Quando você os aplica separadamente, eles devem ser processados ​​separadamente. Sinta-se à vontade para me corrigir se eu estiver errado (e apontar a documentação da Apple sobre isso.)
— 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 de acordo com sua sugestão atualizou a resposta
— damithH

5

Aqui está uma categoria fácil para integrar o efeito no 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
Embora este link possa responder à pergunta, é melhor incluir as partes essenciais da resposta aqui e fornecer o link para referência. As respostas somente com link podem se tornar inválidas se a página vinculada mudar.
— Maciej Swic

Será difícil integrar todo o projeto github aqui
— Bejil

1
Você não precisa trazer todo o projeto, apenas a parte essencial como demonstrei editando a resposta. Isso é para que o código permaneça no caso do Github estar fora do ar, você puxar o repo ou o céu cair.
— Maciej Swic


3

Isso ajudará alguém que está procurando implementar paralaxe para tableView ou collectionView.

  • em primeiro lugar, crie a célula para a visualização da tabela e coloque a visualização da imagem nela.

  • defina a altura da imagem um pouco mais do que a altura da célula. se a altura da célula = 160 deixe a altura da imagem ser 200 (para fazer o efeito de paralaxe e você pode alterá-lo de acordo)

  • coloque essas duas variáveis ​​em seu viewController ou qualquer classe onde seu delegado tableView é estendido

let imageHeight:CGFloat = 150.0
let OffsetSpeed: CGFloat = 25.0
  • adicione o seguinte código na mesma 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))
        }
    }
}
  • onde seriesTabelView é minha UItableview

  • e agora vamos ir para a célula deste tableView e adicionar o seguinte código

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

Se você quiser implementar isso para collectionView, basta alterar tableView vairable para sua variável collectionView

e é isso. não tenho certeza se esta é a melhor maneira. mas funciona para mim. Espero que funcione para você também. e me avise se houver algum problema


2

Realmente muito fácil de fazer isso porque se refere a um código complexo. apenas tente. Trabalhando

Dê uma olhada no imageview exatamente do tamanho da visualização da imagem. por padrão alfa para o conjunto de visualização 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

Tradução 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)
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.