O Auto Layout está dificultando minha vida. Em teoria, seria realmente útil quando eu trocasse, mas pareço lutar contra isso o tempo todo.
Eu fiz um projeto de demonstração para tentar encontrar ajuda. Alguém sabe como aumentar ou diminuir uniformemente os espaços entre as visualizações sempre que a visualização é redimensionada?
Aqui estão três etiquetas (espaçadas manualmente na vertical, mesmo):
O que eu quero é que eles redimensionem seu espaçamento (não o tamanho da visualização) uniformemente quando eu giro. Por padrão, as vistas superior e inferior se comprimem em direção ao centro:
Respostas:
Portanto, minha abordagem permite que você faça isso no construtor de interfaces. O que você faz é criar 'vistas espaçadoras' que você definiu para igualar as alturas igualmente. Em seguida, adicione restrições superiores e inferiores aos rótulos (veja a captura de tela).
Mais especificamente, tenho uma restrição superior em 'Spacer View 1' para supervisionar com uma restrição de altura de prioridade mais baixa que 1000 e com Height Equals para todas as outras 'visualizações de espaçador'. 'Spacer View 4' tem uma restrição de espaço inferior à superview. Cada etiqueta possui uma respectiva restrição superior e inferior às 'vistas espaçadoras' mais próximas.
Nota: verifique se NÃO há restrições adicionais de espaço superior / inferior em seus rótulos para a visualização. apenas aqueles para as 'vistas do espaço'. Isso será satisfatório, pois as restrições superior e inferior estão em 'Space View 1' e 'Spacer View 4', respectivamente.
Duh 1: dupliquei minha visualização e apenas a coloquei no modo paisagem para que você pudesse ver que funcionava.
Duh 2: As 'vistas espaçadoras' poderiam ter sido transparentes.
Duh 3: Essa abordagem pode ser aplicada horizontalmente.
fonte
OLHE, SEM ESPAÇADORES!
Com base nas sugestões na seção de comentários da minha resposta original, especialmente nas sugestões úteis do @ Rivera, simplifiquei minha resposta original.
Estou usando gifs para ilustrar como isso é simples. Espero que você ache os gifs úteis. Caso você tenha um problema com gifs, incluímos a resposta antiga abaixo com capturas de tela simples.
Instruções:
1) Adicione seus botões ou etiquetas. Estou usando 3 botões.
2) Adicione uma restrição de centro x de cada botão à superview:
3) Adicione uma restrição de cada botão à restrição de layout inferior:
4) Ajuste a restrição adicionada no item 3 acima, da seguinte maneira:
a) selecione a restrição, b) remova a constante (defina como 0), c) altere o multiplicador da seguinte forma: pegue o número de botões + 1 e, começando pelo topo, defina o multiplicador como buttonCountPlus1: 1 e, em seguida, buttonCountPlus1 : 2 e finalmente buttonCountPlus1: 3 . (Explico de onde obtive essa fórmula na resposta antiga abaixo, se você estiver interessado).
5) Aqui está uma demonstração em execução!
Nota: Se os botões tiverem alturas maiores, será necessário compensar isso no valor constante, pois a restrição está na parte inferior do botão.
Resposta antiga
Apesar do que dizem os documentos da Apple e o excelente livro de Erica Sadun ( Auto Layout Demystified ), é possível espaçar uniformemente as visualizações sem espaçadores. Isso é muito simples de fazer no IB e no código de qualquer número de elementos que você deseja espaçar uniformemente. Tudo o que você precisa é de uma fórmula matemática chamada "fórmula da seção". É mais simples de fazer do que explicar. Eu farei o meu melhor demonstrando isso no IB, mas é tão fácil de fazer no código.
No exemplo em questão, você faria
1) comece definindo cada etiqueta para ter uma restrição central. Isso é muito simples de fazer. Basta controlar o arrasto de cada etiqueta para o fundo.
2) Mantenha pressionada a tecla Shift, pois você também pode adicionar a outra restrição que usaremos, a saber, o "espaço inferior ao guia de layout inferior".
3) Selecione o "guia de layout do espaço inferior à inferior" e "centralize horizontalmente no recipiente". Faça isso para todos os três rótulos.
Basicamente, se pegarmos o rótulo cuja coordenada queremos determinar e dividi-lo pelo número total de rótulos mais 1, então temos um número que podemos adicionar ao IB para obter o local dinâmico. Estou simplificando a fórmula, mas você pode usá-la para definir o espaçamento horizontal ou vertical e horizontal ao mesmo tempo. É super poderoso!
Aqui estão nossos multiplicadores.
Rótulo1 = 1/4 = 0,25,
Etiqueta2 = 2/4 = 0,5,
Rótulo3 = 3/4 = 0,75
(Edit: @Rivera comentou que você pode simplesmente usar as proporções diretamente no campo multiplicador e xCode com as contas!)
4) Então, vamos selecionar Label1 e selecione a restrição inferior. Como isso:
5) Selecione o "Segundo item" no Inspetor de atributos.
6) No menu suspenso, selecione "Reverter primeiro e segundo itens".
7) Zere a constante e o valor wC hAny. (Você pode adicionar um deslocamento aqui, se necessário).
8) Esta é a parte crítica: no campo multiplicador, adicione nosso primeiro multiplicador 0,25.
9) Enquanto estiver nele, defina o "Primeiro item" no topo como "CentroY", pois queremos centralizá-lo no centro y da etiqueta. Aqui está como tudo isso deve parecer.
10) Repita esse processo para cada etiqueta e conecte o multiplicador relevante: 0,5 para Label2 e 0,75 para Label3. Aqui está o produto final em todas as orientações com todos os dispositivos compactos! Super simples. Estive procurando muitas soluções envolvendo resmas de código e espaçadores. Essa é de longe a melhor solução que eu já vi sobre o assunto.
Atualização: @kraftydevil acrescenta que o guia de layout inferior só aparece nos storyboards, não nos xibs. Use 'Bottom Space to Container' no xibs. Boa pegada!
fonte
Solução muito rápida para o Interface Builder:
Para que qualquer número de visualizações seja uniformemente espaçado em uma superview, basta atribuir a cada uma uma restrição "Alinhar centro X à superview" para o layout horizontal, ou "Alinhar superview Center Y para o layout vertical e defina o Multiplicador como
N:p
( NOTA: alguns tiveram melhor sorte comp:N
- veja abaixo )Onde
N = total number of views
ep = position of the view including spaces
A primeira posição é 1, depois um espaço, fazendo a próxima posição 3, então p se torna uma série [1,3,5,7,9, ...]. Funciona para qualquer número de visualizações.
Portanto, se você tiver três visualizações para espaçar, fica assim:
EDIT Nota: A escolha
N:p
oup:N
depende da ordem da relação da sua restrição de alinhamento. Se "Primeiro Item" for Superview.Center, você poderá usarp:N
, enquanto se Superview.Center for "Segundo Item", poderá usarN:p
. Em caso de dúvida, tente as duas ... :-)fonte
A partir do iOS 9, a Apple tornou isso muito fácil com o (aguardado)
UIStackView
. Basta selecionar as visualizações que você deseja conter no Interface Builder e escolha Editor -> Incorporar -> Visualização da pilha. Defina as restrições de largura / altura / margem apropriadas para a exibição da pilha e defina a propriedade Distribution como 'Espaçamento igual':Obviamente, se você precisar oferecer suporte ao iOS 8 ou inferior, terá que escolher uma das outras opções.
fonte
Estive em uma montanha-russa de autolayout amoroso e odeio. A chave para amar isso parece ser aceitar o seguinte:
Dito isto, o que você está tentando não é simples e seria difícil de obter no construtor de interface. É bem simples de fazer em código. Este código, em
viewDidLoad
, cria e posiciona três rótulos como você está solicitando:Como eu disse, esse código é muito simplificado com alguns métodos de categoria
UIView
, mas, para maior clareza, eu o fiz até aqui.A categoria está aqui para os interessados e possui um método para espaçar uniformemente uma matriz de visualizações ao longo de um eixo específico.
fonte
A maioria dessas soluções depende da existência de um número ímpar de itens para que você possa pegar o item do meio e centralizá-lo. E se você tiver um número par de itens que ainda deseja distribuir igualmente? Aqui está uma solução mais geral. Esta categoria distribuirá uniformemente qualquer número de itens ao longo do eixo vertical ou horizontal.
Exemplo de uso para distribuir verticalmente 4 rótulos em sua superview:
NSLayoutConstraint + EvenDistribution.h
NSLayoutConstraint + EvenDistribution.m
fonte
A maneira correta e mais fácil é usar as Visualizações de pilha.
fonte
Confira a biblioteca de código aberto PureLayout . Ele oferece alguns métodos de API para distribuição de visualizações, incluindo variantes nas quais o espaçamento entre cada visualização é fixo (o tamanho da visualização varia conforme o necessário) e onde o tamanho de cada visualização é fixo (o espaçamento entre as visualizações varia conforme o necessário). Observe que tudo isso é realizado sem o uso de "vistas espaçadoras".
Do NSArray + PureLayout.h :
Como é tudo de código aberto, se você estiver interessado em ver como isso é alcançado sem visualizações espaçadoras, basta dar uma olhada na implementação. (Depende do aproveitamento das restrições
constant
emultiplier
das restrições.)fonte
Estou com um problema semelhante e descobri este post. No entanto, nenhuma das respostas fornecidas atualmente resolve o problema da maneira que você deseja. Eles não fazem o espaçamento igualmente, mas distribuem igualmente o centro dos rótulos. É importante entender que isso não é o mesmo. Eu construí um pequeno diagrama para ilustrar isso.
Existem 3 visualizações, todas com 20pt de altura. O uso de qualquer um dos métodos sugeridos distribui igualmente os centros das vistas e fornece o layout ilustrado. Observe que o centro y das vistas é espaçado igualmente. No entanto, o espaçamento entre a super visão e a vista superior é de 15 pontos, enquanto o espaçamento entre as sub visões é de apenas 5 pontos. Para que as vistas sejam espaçadas igualmente, ambas devem ter 10 pontos, ou seja, todas as setas azuis devem ter 10 pontos.
No entanto, ainda não encontrei uma boa solução genérica. Atualmente, minha melhor idéia é inserir "vistas de espaçamento" entre as subvisões e definir as alturas das vistas de espaçamento iguais.
fonte
Consegui resolver isso totalmente no IB:
Portanto, se você tiver três rótulos, defina os multiplicadores para cada uma dessas restrições como 0,1666667, 0,5, 0,833333.
fonte
Eu encontrei um método perfeito e simples. O layout automático não permite redimensionar os espaços igualmente, mas permite redimensionar as vistas igualmente. Basta colocar algumas visualizações invisíveis entre seus campos e informar ao layout automático para mantê-los do mesmo tamanho. Funciona perfeitamente!
Uma coisa digna de nota; quando reduzi o tamanho no designer de interface, às vezes ele ficava confuso e deixava uma etiqueta onde estava, e havia um conflito se o tamanho fosse alterado por uma quantia ímpar. Caso contrário, funcionou perfeitamente.
editar: descobri que o conflito se tornou um problema. Por causa disso, peguei uma das restrições de espaçamento, a excluí e a substitui por duas restrições, uma maior que ou igual e uma menor que ou igual. Ambos tinham o mesmo tamanho e tinham uma prioridade muito menor do que as outras restrições. O resultado não foi mais conflito.
fonte
Com base na resposta de Ben Dolman, isso distribui as visualizações de maneira mais uniforme (com preenchimento, etc):
fonte
verifique https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/AutoLayoutbyExample/AutoLayoutbyExample.html com uma boa descrição sobre como resolver seu problema.
fonte
Com rótulos, isso funciona bem, pelo menos:
@"H:|-15-[first(==second)]-[second(==third)]-[third(==first)]-15-|
Se o primeiro tiver a mesma largura que o segundo, o segundo e o terceiro e o terceiro e o primeiro, todos terão a mesma largura ... Você pode fazer isso na horizontal (H) e na vertical (V).
fonte
versão rápida 3
fonte
Sei que já faz um tempo desde a primeira resposta, mas me deparei com o mesmo problema e quero compartilhar minha solução. Para as próximas gerações ...
Defino minhas visualizações em viewDidLoad:
E então, no updateViewConstrains, primeiro excluo todas as restrições, depois crio o dicionário de visualizações e depois calculo o espaço a ser usado entre as visualizações. Depois disso, eu apenas uso o Visual Language Format para definir as restrições:
O lado bom desse método é que você precisa fazer muito pouca matemática. Não estou dizendo que esta é a solução perfeita, mas eu trabalho para o layout que estava tentando obter.
Espero que ajude.
fonte
Aqui está uma solução que centralizará verticalmente qualquer número de subvisões, mesmo que elas tenham tamanhos exclusivos. O que você deseja fazer é criar um contêiner de nível médio, centralizar na superview, colocar todas as subvisões no contêiner e organizá-las uma em relação à outra. Mas, crucialmente, você também precisa restringi-los ao topo e inferior do contêiner, para que o contêiner possa ser dimensionado e centralizado corretamente na superview. Ao calcular a altura correta de suas subvisões, o contêiner pode ser centralizado verticalmente.
Neste exemplo,
self
é a superview na qual você está centralizando todas as subviews.fonte
Acabei de resolver meu problema usando o recurso multiplicador. Não sei se funciona para todos os casos, mas para mim funcionou perfeitamente. Estou no Xcode 6.3 FYI.
O que acabei fazendo foi:
1) Primeiro, posicionei meus botões em uma tela de 320px de largura distribuída da maneira que eu queria que fosse em um dispositivo de 320px.
2) Em seguida, adicionei uma restrição de espaço à superview em todos os meus botões.
3) Em seguida, modifiquei as propriedades do espaço inicial para que a constante fosse 0 e o multiplicador seja o deslocamento x dividido pela largura da tela (por exemplo, meu primeiro botão foi 8px da borda esquerda, então defino meu multiplicador como 8/320)
4) O passo importante aqui é alterar o segundo item na relação de restrição para ser a superview.Trailing ao invés de superview.leading. Isso é fundamental porque a superview. Líder é 0 e, no meu caso, é 320, então 8/320 é 8 px em um dispositivo de 320px; quando a largura da superview muda para 640 ou o que for, todas as visualizações se movem em uma proporção relativa à largura do tamanho da tela de 320 pixels. A matemática aqui é muito mais simples de entender.
fonte
Muitas respostas não estão corretas, mas obtém muitas contagens. Aqui, eu apenas escrevo uma solução programaticamente, as três visualizações são alinhadas horizontalmente, sem o uso de visualizações espaçadoras , mas só funcionam quando as larguras dos rótulos são conhecidas quando usadas no storyboard .
fonte
Aqui está mais uma resposta. Eu estava respondendo a uma pergunta semelhante e vi o link referenciado a esta pergunta. Não vi nenhuma resposta semelhante à minha. Então, pensei em escrever aqui.
E, novamente, isso pode ser feito facilmente com o iOS9 UIStackViews também.
Observe que é exatamente a mesma abordagem acima. Ele adiciona quatro vistas de contêineres que são preenchidas igualmente e uma vista é adicionada a cada vista de pilha que está alinhada no centro. Porém, esta versão do UIStackView reduz alguns códigos e fica bonita.
fonte
Outra abordagem pode ser fazer com que os rótulos superior e inferior tenham restrições em relação à vista superior e inferior, respectivamente, e que a vista do meio tenha restrições superiores e inferiores em relação à primeira e terceira vistas, respectivamente.
Observe que você tem mais controle sobre as restrições do que parece arrastando as vistas próximas umas das outras até que as linhas tracejadas apareçam - elas indicam restrições entre os dois objetos que serão formados em vez de entre o objeto e a superview.
Nesse caso, você deseja alterar as restrições para "Maior que ou igual a" o valor desejado, em vez de "igual a" para permitir que elas sejam redimensionadas. Não tenho certeza se isso fará exatamente o que você deseja.
fonte
Maneira muito fácil de resolver isso no InterfaceBuilder:
Defina a etiqueta centralizada (etiqueta2) como "Centro horizontal no contêiner" e "Centro vertical no contêiner"
Selecione a etiqueta centralizada e a etiqueta superior (etiqueta1 + etiqueta2) e adicione DUAS restrições ao espaçamento vertical. Um com Maior ou Igual ao espaçamento mínimo. Um com menos que ou igual ao espaçamento máximo.
O mesmo para a etiqueta centralizada e a etiqueta inferior (etiqueta2 + etiqueta3).
Além disso, você também pode adicionar duas restrições ao label1 - Espaço superior ao SuperView e duas restrições ao label2 - Espaço inferior ao SuperView.
O resultado será que todos os quatro espaçamentos mudarão de tamanho igualmente.
fonte
Eu fiz uma função que pode ajudar. Este exemplo de uso:
fará com que a distribuição vertical (desculpe não ter a reputação de incorporar imagens). E se você alterar o eixo e alguns valores de margem:
Você obterá essa distribuição horizontal .
Eu sou novato no iOS, mas voilà!
EvenDistribution.h
EvenDistribution.m
fonte
Sim, você pode fazer isso apenas no construtor de interfaces e sem escrever código - a única ressalva é que você está redimensionando o rótulo em vez de distribuir espaços em branco. Nesse caso, alinhe os X e Y do Rótulo 2 à super visão para que fique fixo no centro. Em seguida, defina o espaço vertical da etiqueta 1 como a super visão geral e a etiqueta 2 como padrão, repita para a etiqueta 3. Após definir a etiqueta 2, a maneira mais fácil de definir as etiquetas 1 e 3 é redimensioná-las até que elas se encaixem.
Aqui está a exibição horizontal, observe que o espaço vertical entre os rótulos 1 e 2 está definido como padrão:
E aqui está a versão em retrato:
Sei que eles não são absolutamente 100% igualmente espaçados entre as linhas de base devido à diferença entre o espaço padrão entre rótulos e o espaço padrão para a superview. Se isso lhe incomoda, defina o tamanho como 0 em vez de padrão
fonte
Defino um valor de largura apenas para o primeiro item (> = uma largura) e uma distância mínima entre cada item (> = uma distância). Então eu uso Ctrl para arrastar o segundo, o terceiro ... item do primeiro para encadear dependências entre os itens.
fonte
Tarde para a festa, mas eu tenho uma solução funcional para criar um menu horizontalmente com espaçamento. Isso pode ser feito facilmente usando o
==
NSLayoutConstraintfonte
O Android tem um método de encadear visualizações em seu sistema de layout baseado em restrições que eu queria imitar. As pesquisas me trouxeram aqui, mas nenhuma das respostas funcionou. Eu não queria usar o StackViews porque eles tendem a me causar mais tristeza do que economizam na frente. Acabei criando uma solução que usava UILayoutGuides colocados entre as visualizações. Controlar suas larguras permite diferentes tipos de distribuições, estilos de cadeia na linguagem Android. A função aceita uma âncora à esquerda e à direita em vez de uma exibição pai. Isso permite que a cadeia seja colocada entre duas visualizações arbitrárias em vez de distribuída dentro da visualização pai. Ele usa o
UILayoutGuide
que está disponível apenas no iOS 9+, mas isso não deve ser mais um problema.fonte
Eu queria alinhar horizontalmente 5 imagens, então acabei seguindo a resposta do Mete com uma pequena diferença.
A primeira imagem será centralizada horizontalmente no contêiner igual a 0 e um multiplicador de 1: 5:
A segunda imagem será centralizada horizontalmente no contêiner igual a 0 e um multiplicador de 3: 5:
E assim para o resto das imagens. Por exemplo, a quinta (e última) imagem será centralizada horizontalmente no contêiner igual a 0 e um multiplicador de 9: 5:
Como Mete explicou, a ordem vai 1, 3, 5, 7, 9, etc. As posições seguem a mesma lógica: a primeira posição é 1, depois o espaço, depois a próxima posição 3 e assim por diante.
fonte
Por que você simplesmente não cria um tableView e faz
isScrollEnabled = false
fonte