Eu configurei vários conjuntos de restrições em IB e gostaria de alternar programaticamente entre eles dependendo de algum estado. Há uma constraintsA
coleção de outlet, todas marcadas como instaladas do IB, e uma constraintsB
coleção de outlet, todas desinstaladas do IB.
Posso alternar programaticamente entre os dois conjuntos da seguinte maneira:
NSLayoutConstraint.deactivateConstraints(constraintsA)
NSLayoutConstraint.activateConstraints(constraintsB)
Mas ... eu não consigo descobrir quando fazer isso. Parece que eu deveria ser capaz de fazer isso uma vez viewDidLoad
, mas não consigo fazer isso funcionar. Já tentei ligar view.updateConstraints()
e view.layoutSubviews()
depois definir as restrições, mas sem sucesso.
Descobri que, se definir as restrições, viewDidLayoutSubviews
tudo funcionará conforme o esperado. Acho que gostaria de saber duas coisas ...
- Por que estou obtendo esse comportamento?
- É possível ativar / desativar as restrições de viewDidLoad?
fonte
Respostas:
Eu ativo e desativo
NSLayoutConstraints
emviewDidLoad
, e não tenho problemas com isso. Então funciona. Deve haver uma diferença na configuração entre o seu aplicativo e o meu :-)Vou apenas descrever minha configuração - talvez isso possa lhe dar uma pista:
@IBOutlets
para todas as restrições que preciso ativar / desativar.ViewController
, salvo as restrições em propriedades de classe que não são fracas. A razão para isso é que descobri que, após desativar uma restrição, não consegui reativá-la - ela era nula. Portanto, parece que foi excluído ao ser desativado.NSLayoutConstraint.deactivate/activate
como você, eu usoconstraint.active = YES
/ noNO
lugar.view.layoutIfNeeded()
.fonte
.active = false
esperando que fossem ignoradas até que eu as definisse como ativas.Talvez você possa verificar o seu
@properties
, substituirweak
porstrong
.Às vezes, porque
active = NO
definidoself.yourConstraint = nil
, você não poderia usarself.yourConstraint
novamente.fonte
weak
e isso vai resolver.fonte
Acredito que o problema que você está enfrentando se deve ao fato de as restrições não serem adicionadas às visualizações até que AFTER
viewDidLoad()
seja chamado. Você tem várias opções:A) Você pode conectar suas restrições de layout a um IBOutlet e acessá-las em seu código por meio dessas referências. Como as tomadas são conectadas antes do
viewDidLoad()
início, as restrições devem estar acessíveis e você pode continuar a ativá-las e desativá-las.B) Se você deseja usar a
constraints()
função do UIView para acessar as várias restrições, você deve esperar paraviewDidLayoutSubviews()
iniciar e fazê-lo lá, pois esse é o primeiro ponto após a criação de um controlador de visualização a partir de uma ponta que terá quaisquer restrições instaladas. Não se esqueça de ligarlayoutIfNeeded()
quando terminar. Isso tem a desvantagem de que a passagem de layout será executada duas vezes se houver alguma alteração a ser aplicada e você deve garantir que não há possibilidade de que um loop infinito seja disparado.Um breve aviso: restrições desabilitadas NÃO são retornadas pelo
constraints()
método! Isso significa que se você DESATIVAR uma restrição com a intenção de ativá-la novamente mais tarde, precisará manter uma referência a ela.C) Você pode esquecer a abordagem do storyboard e adicionar suas restrições manualmente. Como você está fazendo isso em
viewDidLoad()
, suponho que a intenção seja fazer isso apenas uma vez durante toda a vida útil do objeto, em vez de alterar o layout na hora, então esse deve ser um método aceitável.fonte
Você também pode ajustar a
priority
propriedade para "ativar" e "desativá-los" (valor 750 para ativar e 250 para desativar, por exemplo). Por alguma razão, mudar oactive
BOOL não teve nenhum efeito na minha IU. Não há necessidadelayoutIfNeeded
e pode ser definido e alterado em viewDidLoad ou a qualquer momento depois disso.fonte
viewWillTransition(to:, with:)
ouviewWillLayoutSubviews()
e você pode manter todas as suas restrições alternativas como "instaladas" em um storyboard. A prioridade da restrição não pode mudar de não obrigatória para obrigatória, portanto, use os valores abaixo1000
. Por outro lado, ativar (adicionar) e desativar (remover) restrições funciona apenas emviewDidLayoutSubviews()
e requer a manutenção destrong
@IBOutlet
referências aNSLayoutConstraint
-s.O momento adequado para desativar restrições não utilizadas:
Lembre-se de que isso
viewWillLayoutSubviews
pode ser chamado várias vezes, então não faça cálculos pesados aqui, certo?Observação: se você quiser reativar algumas das restrições posteriormente, sempre armazene a
strong
referência a elas.fonte
viewDidLayoutSubviews()
. Ajustar as restrições emviewWillLayoutSubviews()
não funciona no meu caso.Quando uma visualização está sendo criada, os seguintes métodos de ciclo de vida são chamados em ordem:
Agora, às suas perguntas.
Resposta: Porque quando você tenta definir as restrições nas vistas,
viewDidLoad
a vista não tem seus limites, portanto, as restrições não podem ser definidas. Só depoisviewDidLayoutSubviews
que os limites da visualização são finalizados.Resposta: Não. Motivo explicado acima.
fonte
Eu descobri, desde que você configure as restrições por normal na substituição de
- (void)updateConstraints
(objetivo c), com umastrong
referência para a inicialidade usada restrições ativas e não ativas. E em outra parte do ciclo de visualização, desative e / ou ative o que você precisa e, em seguidalayoutIfNeeded
, ligue para que não haja problemas.O principal é não reutilizar constantemente a substituição de
updateConstraints
e separar as ativações das restrições, contanto que você chameupdateConstraint
s após sua primeira inicialização e layout. Depois disso, parece importar onde no ciclo de exibição.fonte