iOS: como animar para uma nova restrição de layout automático (altura)

123

Eu nunca trabalhei com restrições de autolayout antes. Estou trabalhando em um novo aplicativo pequeno e notei que as visualizações do NIB estão padronizadas para o autolayout. Então, pensei em aproveitar a oportunidade para trabalhar com ele e tentar descobrir para onde a Apple está indo com isso.

Primeiro desafio:

Preciso redimensionar um MKMapView e gostaria de animá-lo para a nova posição. Se eu fizer isso da maneira que estou acostumado:

[UIView animateWithDuration:1.2f
     animations:^{
         CGRect theFrame = worldView.frame;
         CGRect newFrame = CGRectMake(theFrame.origin.x, theFrame.origin.y, theFrame.size.width, theFrame.size.height - 170);
         worldView.frame = newFrame;
}];

... então o MKMapView retornará à sua altura original sempre que uma visão de irmão for atualizada (no meu caso, o título de um UISegmentedControl está sendo atualizado [myUISegmentedControl setTitle:newTitle forSegmentAtIndex:0]).

Então, o que eu acho que quero fazer é alterar as restrições do MKMapView de serem iguais à altura da visualização pai para serem relativas ao topo do UISegmentedControl que ele estava cobrindo:V:[MKMapView]-(16)-[UISegmentedControl]

O que eu quero é que a altura do MKMapView diminua para que alguns controles abaixo da visualização do mapa sejam revelados. Para fazer isso, acho que preciso alterar a restrição de uma exibição em tamanho fixo fixa para uma em que a parte inferior esteja restrita à parte superior de um UISegmentedControl ... e gostaria que ela fosse animada à medida que a exibição diminui para um novo tamanho.

Como alguém faz isso?

Editar - esta animação não está animada, embora a parte inferior da exibição suba 170 instantaneamente:

    [UIView animateWithDuration:1.2f
         animations:^{
             self.nibMapViewConstraint.constant = -170;

    }];

e o nibMapViewConstraintestá conectado no IB à restrição de espaço vertical inferior.

Meltemi
fonte
1
Eu sei que você pode facilmente alterar o valor constante da restrição em um bloco [UIView animateWithDuration ..] para animar a alteração de altura. Você precisa criar um IBOutlet para essa restrição e conectá-lo no seu xib, ou manter uma referência a ele se você o criou no código (ou percorre todas as restrições para procurá-lo). Não sei como animar as alterações relatedBy, mas li que você deve alterar apenas os valores constantes e não outros de uma restrição (para outros valores, crie uma nova restrição).
yuf 8/11/12
Hmm. pensei que poderia, mas eu sou, não está animando. Ele muda com sucesso e está no bloco de animação, mas não está animando!?!
Meltemi
Encontrei minha resposta aqui: < stackoverflow.com/questions/12926566/… >
Meltemi
1
Não se esqueça do [view layoutIfNeeded], esse foi meu problema também haha. Essa é a mesma pergunta que resolveu meu problema.
yuf 9/11/12
Possível duplicata de Como animar alterações de restrição?
Sensuous

Respostas:

179

Depois de atualizar sua restrição:

[UIView animateWithDuration:0.5 animations:^{[self.view layoutIfNeeded];}];

Substitua self.viewpor uma referência à vista que contém.

Ed McManus
fonte
4
que funciona para a própria exibição, no entanto, as exibições que têm restrições a essa exibição são movidas instantaneamente. O que eu faço? ty
dietbacon
7
você também precisará chamar o layout, se necessário, nessas visualizações. no entanto, ele realmente não funciona corretamente, pois isso também anima a atualização da exibição. Como você anima o ajuste de restrição apenas nas outras visualizações?
N24 24/08
3
Cuidado: Se usar as UIViewAnimationOptionBeginFromCurrentStaterestrições de layout, será definido ANTES da animação!
Robert
12
Em vez de chamar layoutIfNeededpara cada um desses pontos de vista, simplesmente chamar[[self.view superview] layoutIfNeeded];
Flying_Banana
2
@ngb você precisa alterar a constante de restrição dentro do bloco de animação. Dessa forma, a restrição muda com a animação e você pode continuar usando UIViewAnimationOptionBeginFromCurrentState.
Eran Goldin
86

Isso funciona para mim (iOS7 e iOS8 +). Clique na restrição de layout automático que você deseja ajustar (no construtor de interface, por exemplo, restrição superior). Em seguida, faça disso um IBOutlet;

@property (strong, nonatomic) IBOutlet NSLayoutConstraint *topConstraint;

Animar para cima;

    self.topConstraint.constant = -100;    
    [self.viewToAnimate setNeedsUpdateConstraints]; 
    [UIView animateWithDuration:1.5 animations:^{
        [self.viewToAnimate layoutIfNeeded]; 
    }];

Animar de volta ao local original

    self.topConstraint.constant = 0;    
    [self.viewToAnimate setNeedsUpdateConstraints];  
    [UIView animateWithDuration:1.5 animations:^{
        [self.viewToAnimate layoutIfNeeded];
    }];
DevC
fonte
2
UAU!! Isso realmente funciona! Essa resposta me abriu os olhos. Muito obrigado! - Erik
Erik van der Neut
2
@ErikvanderNeut também foi para mim, feliz por ter sido útil. A partir de agora, vou animar restrições em vez da posição dos quadros.
DevC
não deixe de adicionar: [containerView layoutIfNeeded]; Ele garante que todas as operações de layout pendentes tenham sido concluídas ANTES do bloco animateWithDuration.
ingconti
11

Existe um tutorial muito bom da própria Apple que explica como usar a animação com o layout automático. Siga este link e encontre o vídeo chamado "Layout automático por exemplo" Ele fornece algumas informações interessantes sobre o layout automático e a última parte é sobre como usar animação.

Glenn
fonte
3

Eu disponibilizei esta pequena demonstração . Ele mostra como as restrições de layout automático podem ser alteradas e animadas em um exemplo muito simples. Basta dar uma olhada no DemoViewController.m .

Jens Schwarzer
fonte
1

A maioria das pessoas usa o layout automático para criar itens de layout nas visualizações e modificar as restrições de layout para criar animações.

Uma maneira fácil de fazer isso sem muito código é criar o UIView que você deseja animar no Storyboard e, em seguida, criar um UIView oculto onde você deseja que o UIView termine. Você pode usar a visualização no xcode para garantir que os dois UIViews estejam onde você deseja que eles estejam. Depois disso, oculte o UIView final e troque as restrições de layout.

Existe um podfile para trocar restrições de layout chamado SBP, se você não quiser escrevê-lo.

Aqui está um tutorial .

Arjay Waran
fonte
0

Não é necessário usar mais IBOutlet referencerestrições, em vez disso, você pode aplicar direta accessou updatejá a restrição aplicada por Programmaticallyou a partir Interface Builderde qualquer visualização usando a KVConstraintExtensionsMasterbiblioteca. Esta biblioteca também está gerenciando o Cumulativecomportamento de NSLayoutConstraint.

Para adicionar restrição de altura no containerView

 CGFloat height = 200;
 [self.containerView applyHeightConstrain:height];

Para atualizar a restrição de altura do containerView com animação

[self.containerView accessAppliedConstraintByAttribute:NSLayoutAttributeHeight completion:^(NSLayoutConstraint *expectedConstraint){
        if (expectedConstraint) {
            expectedConstraint.constant = 100;

            /* for the animation */ 
            [self.containerView  updateModifyConstraintsWithAnimation:NULL];
      }
    }];
keshav vishwkarma
fonte