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.