Posso desativar o autolayout para uma subvisualização específica em tempo de execução?

104

Eu tenho uma visão que precisa ter seu quadro manipulado programaticamente - é um tipo de visão de documento que envolve seu conteúdo, que é então rolado e ampliado ao redor de uma super visão manipulando a origem do quadro. Autolayout luta com isso em tempo de execução.

Desativar o autolayout completamente parece um pouco difícil porque poderia ser razoavelmente usado para lidar com o layout das outras visualizações. Parece que o que eu quero é algum tipo de "restrição nula".

memória terrível
fonte

Respostas:

168

Eu tive o mesmo problema. Mas eu resolvi isso.
Sim, você pode desabilitar o layout automático em tempo de execução para um determinado UIView, em vez de desabilitá-lo para todo o xib ou storyboard que é definido por padrão no Xcode 4.3 e posterior.

Defina translatesAutoresizingMaskIntoConstraintscomo YES, antes de definir o quadro de sua subvisualização:

self.exampleView.translatesAutoresizingMaskIntoConstraints = YES;
self.exampleView.frame = CGRectMake(20, 20, 50, 50);
Muhammad Aamir Ali
fonte
2
Isso parece um exagero para alguns casos mais complicados com muitas visualizações. Para algo tão simples como isso, está tudo bem.
esh
@MuhammadAamirALi remover a subvisão e adicioná-la novamente pode diminuir o desempenho. Podemos arquivar uma solução melhor?
Nhat Dinh,
2
@DinhNhat eu esclareci a resposta. Não é necessário remover e adicionar novamente a subvisualização.
Leandros
5
Ele me mostra um aviso: "Incapaz de satisfazer as restrições simultaneamente."
NSPratik
1
Você salvou meu dia ... translatesAutoresizingMaskIntoConstraints ... que inventa propriedades como essa cabeça de tremer
Tintenklecks
50

Eu tive um problema semelhante onde o Autolayout estava substituindo algumas das minhas configurações de quadro em tempo de execução (eu tinha uma visão dinâmica que, em alguns casos, empurrava um novo controlador de visão ... apertar e depois pressionar Voltar redefinia a visão inicial).

Eu contornei isso colocando meu código de manipulação no viewDidLayoutSubviewsmeu View Controller. Parece ser chamado depois de qualquer restrição que o mojo seja chamado, mas antes de viewDidAppear, de modo que o usuário não percebe.

jmstone617
fonte
1
Não funciona para self.navigationItem.titleView. Ainda não respeita a mudança de frame.
Henrik Erlandsson
1
Se você está tentando muck com o quadro de uma visualização de título, eu colocaria dentro de uma visualização de contêiner e adicionaria a visualização de contêiner como uma visualização personalizada do NavigationItem.
jmstone617
2
Isso funcionou para mim também. Eu tinha perdido 2h: 22m batendo minha cabeça contra a parede proverbial antes de descobrir esta solução alternativa.
TMc
Obrigado, cara. Estou no segundo dia lutando com esse problema e agora funciona!
apostolov
28

Talvez apenas definir translatesAutoresizingMaskIntoConstraintscomo YES(e não adicionar restrições adicionais que afetam essa visualização) permitirá que você defina o quadro sem lutar contra o sistema de layout automático.

Jon Hull
fonte
17

No iOS 8, você pode definir um NSLayoutConstraint para estar ativo ou não. Portanto, se estou usando o construtor de interface, adiciono todas as minhas restrições a um OutletCollection e, em seguida, ativo ou desativo usando:

NSLayoutConstraint.deactivateConstraints(self.landscapeConstraintsPad)
NSLayoutConstraint.activateConstraints(self.portraitConstraintsPad)

O aplicativo específico para o qual estou usando aqui está tendo diferentes restrições no modo retrato e paisagem e eu ativo / desativo com base na rotação do dispositivo. Isso significa que posso criar algumas alterações de layout complexas no construtor de interface para ambas as orientações e ainda usar o layout automático sem o código de layout automático detalhado.

Ou você pode ativar / desativar usando removeConstraints e addConstraints.

bandejapaisa
fonte
Desculpe por sequestrar uma pergunta tão antiga, mas posso perguntar como você conseguiu adicionar restrições de layout para layouts diferentes em primeiro lugar? Não consigo encontrar uma opção dentro do construtor de interface para habilitar / desabilitar restrições. Ou você simplesmente adicionou restrições para ambos os layouts e simplesmente ignorou o construtor de interface reclamando sobre restrições inválidas (sobreposição)?
Malte
Bem, você poderia fazer isso usando classes de tamanho: developer.apple.com/library/ios/recipes/… , mas eu não poderia fazer dessa forma porque eu estava oferecendo suporte ao iOS 7 também e classes de tamanho não são totalmente compatíveis com iOS 7 Eu fiz isso diminuindo a prioridade da restrição conflitante. Não é o ideal, mas evita o aviso. Eu acho que eu fiz assim mesmo ....
bandejapaisa
9

Não sei se isso vai ajudar mais alguém, mas escrevi uma categoria para tornar isso conveniente porque me pego fazendo muito isso.

UIView + DisableAutolayoutTemporously.h

#import <UIKit/UIKit.h>

@interface UIView (DisableAutolayoutTemporarily)

// the view as a parameter is a convenience so we don't have to always
// guard against strong-reference cycles
- (void)resizeWithBlock:(void (^)(UIView *view))block;

@end

UIView + DisableAutolayoutTemporously.m

#import "UIView+DisableAutoResizeTemporarily.h"
@implementation UIView (DisableAutoResizeTemporarily)

- (void)resizeWithBlock:(void (^)(UIView * view))block
{
    UIView *superview = self.superview;
    [self removeFromSuperview];
    [self setTranslatesAutoresizingMaskIntoConstraints:YES];
    __weak UIView *weakSelf = self;
    block(weakSelf);
    [superview addSubview:self];
}

@end

Eu uso assim:

[cell.argumentLabel resizeWithBlock:^(UIView *view) {
    [view setFrame:frame];
}];

Espero que ajude.

Michaelsnowden
fonte
Brilhante! Usei uma versão modificada do seu código para escrever uma função simples "hideControl" para qualquer UIView. Basicamente, ele define a altura de um UIView como 0, mas, crucialmente, usa seu código para fazer o AutoLayout tratá-lo corretamente (ao contrário de "someView.hidden = TRUE"). Assim, os controles que apareciam abaixo do controle oculto, e tinham espaçamento vertical vinculado a ele, agora se deslocariam para cima na tela para preencher a lacuna, onde a visualização oculta aparecia anteriormente.
Mike Gledhill
6

Você pode definir o translatesAutoresizingMaskIntoConstraintstipo Boolean, Valor Sim nos Atributos de tempo de execução definidos pelo usuário do UIView que deseja no xib / storyboard.

renaun
fonte
2
  • Abra o projeto em 4.5
  • Selecione o storyboard
  • Abra o inspetor de arquivos
  • Em Interface Builder Document, desmarque 'Use Autolayout'

Você pode dividir em vários storyboards se quiser usar o layout automático para algumas visualizações.

Mike Bobbitt
fonte
10
Isso desativa o layout automático para todo o storyboard / ponta. O que eu procurava era uma maneira (idealmente programática) de fazer com que subvisualizações específicas em um storyboard / nib não usassem autolayout, deixando o resto fazendo tudo o que o storyboard / nib especificou.
terrível
Você poderia usar vários storyboards e apenas invocar aqueles com / sem autolayout conforme necessário: // Inicializar o controlador de storboard e visualização de detalhes para exibir UIStoryboard * sb = [UIStoryboard storyboardWithName: @ pacote "Storyboard": [NSBundle mainBundle]]; DetailViewController * dvController = [sb instantiateViewControllerWithIdentifier: entry.viewName];
Mike Bobbitt
1

Para mim, funcionou criar a subvisualização programaticamente; no meu caso, o layout automático estava bagunçando uma visão que eu precisava girar em torno de seu centro, mas depois que criei essa visão programaticamente, ela funcionou.

Andrespch
fonte
1

Na minha opinião, eu tinha um rótulo e um texto. O rótulo tinha gesto de pan. O rótulo se move bem durante o arrasto. Mas quando eu uso o teclado de caixa de texto, o rótulo redefine sua posição para o local original definido no layout automático. O problema foi resolvido quando adicionei o seguinte rapidamente para o rótulo. Eu adicionei isso em viewWillAppear, mas pode ser adicionado em qualquer lugar onde você tenha acesso ao campo de destino.

self.captionUILabel.translatesAutoresizingMaskIntoConstraints = true
Big D
fonte
0

Isso aconteceu comigo em um projeto sem storyboards ou arquivos xib. Todo o código 100%. Eu tinha um banner de anúncio na parte inferior e queria que os limites de visualização parassem no banner de anúncio. A visualização seria redimensionada automaticamente após o carregamento. Tentei todas as resoluções desta página, mas nenhuma funcionou.

Acabei criando apenas uma visualização secundária com a altura reduzida e coloquei-a na visualização principal do controlador. Então, todo o meu conteúdo foi para a sub view. Isso resolveu o problema facilmente, sem fazer nada que parecesse ir contra a corrente.

Eu estou pensando se você quer uma visão que não seja do tamanho normal que preenche a janela, então você deveria usar uma visão secundária para isso.

RandallTo
fonte
0

Encontrei um cenário semelhante, onde me juntei a um projeto que foi iniciado com layout automático, mas precisei fazer ajustes dinâmicos em várias visualizações. Aqui está o que funcionou para mim:

  1. NÃO tenha visualizações ou componentes dispostos no construtor de interface.

  2. Adicione suas visualizações de forma puramente programática, começando com aloc / init e configurando seus quadros de maneira apropriada.

  3. Feito.

Sim.
fonte
0

Em vez de desativar o autolayout, eu apenas calcularia a nova restrição com o quadro que você está substituindo. Essa parece-me a forma adequada. Se você estiver ajustando componentes que dependem de restrições, ajuste-os de acordo.

Por exemplo, se você tem uma restrição vertical de 0 entre duas visualizações (myView e otherView) e tem um gesto panorâmico ou algo que ajusta a altura de myView, você pode recalcular a restrição com os valores ajustados.

self.verticalConstraint.constant = newMyViewYOriginValue - (self.otherView.frame.origin.y + self.otherView.frame.size.height);
[self.myView needsUpdateConstraints];
Myles Caley
fonte
0

Para aqueles de vocês que estão usando o layout automático, confira minha solução aqui . Você deve fazer @IBOutletas restrições que deseja ajustar e, em seguida, alterar suas constantes.

Mike
fonte
-16

se for um arquivo xib:

  1. selecione o arquivo .xib
  2. selecione o "Proprietário do Arquivo"
  3. mostrar os utilitários
  4. clique em: "Inspetor de arquivos"
  5. Em "Interface Builder Document", desative: "Use Autolayout"
Alish
fonte
1
Não, isso desativa o autolayout para todo o xib. O que eu estava procurando é uma maneira de tirar apenas uma subvisualização específica do sistema de layout automático.
memória