Eu sei que a cadeia de layout automático consiste basicamente em 3 processos diferentes.
- atualizando restrições
- visualizações de layout (aqui é onde obtemos o cálculo de quadros)
- exibição
O que não está totalmente claro para mim é a diferença interior entre -setNeedsLayout
e -setNeedsUpdateConstraints
. Do Apple Docs:
Chame esse método no thread principal do seu aplicativo quando desejar ajustar o layout das subvisões de uma exibição. Este método anota a solicitação e retorna imediatamente. Como esse método não força uma atualização imediata, mas aguarda o próximo ciclo de atualização, você pode usá-lo para invalidar o layout de várias visualizações antes que qualquer uma dessas visualizações seja atualizada. Esse comportamento permite consolidar todas as atualizações de layout em um ciclo de atualização, o que geralmente é melhor para o desempenho.
Quando uma propriedade de sua visualização personalizada é alterada de maneira a afetar as restrições, você pode chamar esse método para indicar que as restrições precisam ser atualizadas em algum momento no futuro. O sistema chamará updateConstraints como parte de seu passe de layout normal. A atualização de restrições de uma só vez antes de serem necessárias garante que você não recalcule desnecessariamente as restrições quando várias alterações são feitas na sua visualização entre as passagens de layout.
Quando eu quero animar uma exibição depois de modificar uma restrição e animar as alterações que eu costumo chamar, por exemplo:
[UIView animateWithDuration:1.0f delay:0.0f usingSpringWithDamping:0.5f initialSpringVelocity:1 options:UIViewAnimationOptionCurveEaseInOut animations:^{
[self.modifConstrView setNeedsUpdateConstraints];
[self.modifConstrView layoutIfNeeded];
} completion:NULL];
Eu descobri que se eu usar -setNeedsLayout
em vez de -setNeedsUpdateConstraints
tudo funcionar como esperado, mas se eu mudar -layoutIfNeeded
com -updateConstraintsIfNeeded
, a animação não vai acontecer.
Eu tentei fazer minha própria conclusão:
-updateConstraintsIfNeeded
atualiza apenas as restrições, mas não força o layout a entrar no processo; portanto, os quadros originais ainda são preservados-setNeedsLayout
chama também-updateContraints
método
Então, quando é bom usar um em vez do outro? e sobre os métodos de layout, preciso chamá-los na exibição que possui uma alteração em uma restrição ou na exibição pai?
Respostas:
Suas conclusões estão certas. O esquema básico é:
setNeedsUpdateConstraints
garante uma futura chamada paraupdateConstraintsIfNeeded
chamadasupdateConstraints
.setNeedsLayout
garante uma futura chamada paralayoutIfNeeded
chamadaslayoutSubviews
.Quando
layoutSubviews
é chamado, também chamaupdateConstraintsIfNeeded
, portanto, raramente é necessário chamá-lo manualmente. Na verdade, nunca o chamei, exceto ao depurar layouts.A atualização de restrições usando também
setNeedsUpdateConstraints
é bastante rara, objc.io - é necessário ler sobre os layouts automáticos - diz :Além disso, na minha experiência, nunca tive que invalidar restrições e não definir
setNeedsLayout
na próxima linha do código, porque novas restrições praticamente exigem um novo layout.As regras práticas são:
setNeedsLayout
.updateConstraints
método (a maneira recomendada para restrições de mudança, btw), chamadasetNeedsUpdateConstraints
, e na maioria das vezes,setNeedsLayout
depois disso.layoutIfNeeded
.Além disso, no seu código de animação, acredito que não
setNeedsUpdateConstraints
é necessário, pois as restrições são atualizadas manualmente antes da animação, e a animação apenas re-expõe a exibição com base nas diferenças entre as antigas e as novas.fonte
setNeedsLayout
.setNeedsLayout
garante quelayoutSubviews
será chamado no próximo ciclo de atualização, mas talvez isso não tenha nada a ver com issolayoutIfNeeded
?layoutSubviews
será chamado automaticamente, sem necessidade de chamarsetNeedsLayout
layoutSubviews
, portanto, não é necessário fazê-lo manualmente. Você, no entanto, tem que chamarlayoutIfNeeded
se precisar que as alterações tenham efeito imediato, em vez do próximo ciclo de layoutA resposta do coverback é bastante correta. No entanto, gostaria de adicionar alguns detalhes adicionais.
Abaixo está o diagrama de um ciclo UIView típico que explica outros comportamentos:
-setNeedsLayout
em vez de-setNeedsUpdateConstraints
tudo funcionar como esperado, mas se eu mudar-layoutIfNeeded
com-updateConstraintsIfNeeded
, a animação não vai acontecer.updateConstraints
normalmente não faz nada. Ele apenas resolve restrições que não as aplica até quelayoutSubviews
seja chamado. Portanto, a animação requer uma chamada paralayoutSubviews
.Não, isso não é necessário. Se suas restrições não foram modificadas, o UIView passará a chamada para
updateConstraints
. Você precisa chamar explicitamentesetNeedsUpdateConstraint
para modificar restrições no processo.Para ligar,
updateConstraints
você precisa fazer o seguinte:fonte