Como posso usar o Autolayout para definir restrições no meu UIScrollview?

176

Passei dois dias testando as várias soluções para abordagens de Autolayout misto e puro para obter o que era uma configuração trivial de scrollview antes do autolayout, e agora é oficial - devo ser muito estúpido. Estou configurando isso principalmente no Storyboard (bem, é do jeito que está).

Então aqui está o meu pedido de ajuda.

Viewtree:

UIView
-UIView
-UIView
..-UIScrollview
...-UIButton
...-UIButton
...-UIButton

Os botões devem rolar horizontalmente (da esquerda para a direita e vice-versa). Alguém pode por favor deixe-me saber como definir as limitações para alcançar este objectivo usando puro AutoLayout ???

-

Eu tentei a abordagem mista, assim:

UIView
- UIView
- UIView
..-UIScrollview
...-UIView (contentview)
....-UIButton
....-UIButton
....-UIButton

... e definir restrições fixas de largura e altura para contentviewas translatesAutoresizingMaskIntoConstraintsconfigurações e de acordo com a Nota técnica da Apple. Os botões e a visualização de rolagem são configurados usando restrições. Isso obtém a rolagem do scrollview (yay), mas, infelizmente, ele rola muito longe! Tanto quanto eu posso dizer, a largura da rolagem é de alguma forma duplicada do que eu defini a visualização do conteúdo em ??? !!!

Tentei também a abordagem de autolayout puro, com contentviewe sem. Todas as visualizações são translatesAutoresizingMaskIntoConstraints=NO, exceto self.view. Os botões têm restrições fixas de largura / altura e são fixados nas quatro arestas da visualização de rolagem. Nada rola.

Por isso, estou totalmente perplexo porque não consigo fazê-lo funcionar corretamente. Qualquer ajuda é muito apreciada, e se você precisar de outras informações, pergunte!

ATUALIZADO Screenshot com solução - restrições buttonZ:

insira a descrição da imagem aqui

EDIT @ Jamie Forrest Portanto, a solução acaba sendo a restrição à direita no último botão. Em vez de 6441, o valor que eu havia definido era negativo, -6441. O mais complicado é que, ao definir o valor no storyboard, há duas opções na barra de ferramentas Pin:

insira a descrição da imagem aqui

O valor atual da tela é negativo (levando a nenhuma rolagem), e a opção abaixo é positiva (ativação da rolagem). Isso significa que eu não sou estúpido, mas pelo menos meio cego, eu acho. Embora, em minha defesa, não seja um pouco perturbador o fato de o XCode não mostrar um erro para a configuração "incorreta"?

EDITADO NOVAMENTE Agora, isso é engraçado ... alterar o valor à direita de -6441 (sem rolagem) para 6441 rolagem ativada. Mas meu velho amigo, o "muito conteúdo" estava de volta, levando a um tamanho de conteúdo duas vezes maior do que deveria ser! A solução para obter a rolagem correta do conteúdo foi definir a restrição à direita como ZERO! Isso não é óbvio ao trabalhar no Storyboard, mas ao olhar para o código do @Infinity James, é o que deveria ser.

user1459524
fonte
Onde você calcula / define o tamanho do conteúdo para sua visualização de rolagem? Referindo-se à sua primeira tentativa de usar um contentView, você disse que ele rola demais.
Tim
2
Tanto quanto eu sei, você não pode definir contentSizeum de UIScrollViewapenas usando o layout automático. E é isso contentSizeque define quanto você pode rolar. Então, você precisará definir isso manualmente em algum lugar eventualmente. De resto, você pode usar restrições de layout para configurar os quadros de vista um em relação ao outro.
Guillaume
@ Jeff, o tamanho do conteúdo é fixo, nunca muda. Defino o tamanho do conteúdo no storyboard inserindo manualmente a altura e a largura corretas para a visualização de conteúdo e fixo a altura e a largura com restrições no storyboard.
user1459524
Imprima seu contentSize em tempo de execução, verifique se ele corresponde aos valores que você inseriu. O contentSize determina a quantidade de rolagem, portanto, o problema com sua primeira tentativa é o contentSize.
Tim
@ Guillaume, então a abordagem de "autolayout puro" não é tão pura, afinal? Mas como eu defino o contentSize manualmente? Como mencionei acima, estou definindo a altura / largura da exibição do conteúdo em valores fixos (no storyboard). Mas rola demais (2x).
user1459524

Respostas:

68

É difícil ver os valores exatos e a configuração de suas restrições conforme você as colou aqui, por isso não tenho certeza de olhar para as capturas de tela onde você errou.

Em vez de explicar o que está errado na sua configuração, criei um projeto de amostra básico com uma hierarquia de exibição e restrição de exibição muito semelhante à que você descreve. A rolagem horizontal funciona conforme o esperado no projeto de exemplo, que usa a abordagem "Pure AutoLayout" descrita pela Apple na Nota técnica .

Também tive muitos problemas para conseguir o Auto Layout para trabalhar UIScrollView. A chave para fazê-lo funcionar é garantir que todos os itens da exibição de rolagem, juntos, tenham restrições que eventualmente se vinculem a todos os lados da exibição de rolagem e que contribuam para que o sistema AutoLayout possa determinar um contentSize para o exibição de rolagem que será maior que seu quadro. Parece que você estava tentando fazer isso no seu código, mas talvez houvesse algumas restrições supérfluas que estavam tornando o contentSize muito pequeno.

Além disso, como outros mencionados, com AutoLayout e UIScrollview, você não define mais o contentSize explicitamente. O sistema de AutoLayout calcula o contentSize com base em suas restrições.

Também achei este capítulo de e-book muito útil para me fazer entender como tudo isso funciona. Espero que tudo isso ajude.

Jamie Forrest
fonte
2
OBRIGADO pelo projeto de amostra! Funciona e, enquanto procurava, não encontrei nenhuma diferença no meu projeto a princípio! Copiei as visualizações no meu projeto, suspeitando de alguma outra configuração além de restrições, mas ele continuou a funcionar. Isso me levou a notar que a restrição à direita do último botão do meu projeto tem um negativo - na frente, enquanto o seu tem um valor positivo! A alteração de - para positivo ativou a rolagem! Quando eu mostro a barra de ferramentas Pin, há duas opções: Use o valor Current Canvas, que é negativo, e Scroll View (use current value), que é positivo ...?!
user1459524
Ah sim. O valor negativo na verdade tornaria o contentSize da exibição de rolagem menor, para corresponder ao fato de que a borda à direita deve terminar antes que o botão termine. Fico feliz que o projeto de amostra ajudou!
Jamie Forrest
Isso fez muito. Confira minha resposta atualizada. O valor à direita deve realmente ser 0 (zero) ao que parece.
user1459524
6
Isso é triste, temos que compartilhar capturas de tela em vez de código. Isso ocorre porque a Apple incentiva os desenvolvedores a usar o construtor em vez de fornecer uma API melhor.
Vladimír Slavík 15/05
4
Totalmente não intuitivo. Os desenvolvedores precisam desperdiçar horas e horas para descobrir o que estava acontecendo na mente dos criadores do XCode.
1928 Josh
49

LOL bem-vindo ao clube da estupidez. Eu sou um dos fundadores. : D

Para rolagem VERTICAL : a única maneira de fazê-lo funcionar (iOS 8, Xcode 6 e autolayout puro) era adicionar as seguintes restrições à minha Visualização de rolagem (todas relacionadas à superview):

  • Larguras iguais
  • Equal Heights
  • Alinhamento ao centro Y
  • Alinhamento ao Centro X

Minha estrutura:

  UIView
   - ScrollView
    - Subview
    - Subview
    - Subview
    - Subview
    - ...

Esse é o resultado final:

Demo

Esta é a configuração:

Configuração Tela cheia

E aqui está o projeto .

Felizmente, isso salvaria alguém de DORMIR às 5 da manhã. : D

barra invertida-f
fonte
Muito obrigado pela ajuda! Como você conseguiu a subview do tipo "subview" ?? Estou olhando para o seu projeto no Xcode 6.2, e ele chama esses pequenos retângulos de "Subview", com a única restrição de que ele tem 63px de altura.
Andrew K
1
Saudações! Esse "Subview" é realmente um UIVIew. Isso é apenas um nome ... Você pode digitar qualquer coisa lá. Confira esta imagem: cl.ly/image/291f1K2N0V3p No tópico restrição, as subvisões têm mais do que apenas uma restrição de altura. Confira toda a lista de restrição para esses pontos de vista aqui: cl.ly/image/3l061i123j2i
barra invertida-f
1
Ainda não consigo fazer a rolagem funcionar - notei que as visualizações de suas subvisões estão "acinzentadas" no seu projeto. Depois de fazer algumas pesquisas, parece que você está usando 'classes de tamanho'. Como isso afeta a rolagem? Existe uma maneira de fazer a rolagem funcionar sem usar isso?
Andrew K
Além disso, como você tornou sua superview muito mais longa que o tamanho padrão? Estou tentando adicionar botões que aparecerão "abaixo da dobra" (ou fora da tela), mas obviamente não posso adicioná-los à superview se não consigo arrastá-los e soltá-los na superview, pois ela não é grande o suficiente.
Andrew K
1
depois de um longo dia pesquisando e tentando fazer esse layout de estupidez, encontrei esta resposta e funcionou na primeira tentativa .. Obrigado, cara .. você salvou meu dia .. Gostaria de poder dar milhares de votos a esta resposta ..: )
Bobby Stenly
32

Exemplo autônomo simples

A julgar pelo alto número de votos na pergunta e pelo baixo número de votos nas respostas, as pessoas não encontram aqui uma solução rápida e compreensível. Deixe-me tentar adicionar um. Este projeto é um exemplo independente feito completamente no Interface Builder. Você deve poder trabalhar com ele em 10 minutos ou menos. Em seguida, você pode aplicar os conceitos que aprendeu ao seu próprio projeto.

insira a descrição da imagem aqui

A pergunta original pergunta sobre os botões de rolagem. Aqui eu apenas uso UIViews, mas eles podem representar a visualização que você quiser. Também escolhi a rolagem horizontal porque as capturas de tela do storyboard são mais compactas para este formato. Os princípios são os mesmos para a rolagem vertical, no entanto.

Conceitos chave

  • O UIScrollViewdeve usar apenas uma subvisão. Este é um 'UIView' que serve como visualização de conteúdo para armazenar tudo o que você deseja rolar.
  • Faça com que a exibição de conteúdo e o pai da exibição de rolagem tenham alturas iguais para rolagem horizontal. (Larguras iguais para rolagem vertical)
  • Verifique se todo o conteúdo rolável tem uma largura definida e está fixado em todos os lados.

Iniciar um novo projeto

Pode ser apenas um aplicativo de visualização única.

Storyboard

Neste exemplo, faremos uma visualização de rolagem horizontal. Selecione o View Controller e, em seguida, escolha Freeform no Size Inspector. Faça a largura 1,000e a altura 300. Isso nos dá espaço no storyboard para adicionar conteúdo que será rolado.

insira a descrição da imagem aqui

Adicionar uma visualização de rolagem

Adicione um UIScrollViewe fixe todos os quatro lados à visualização raiz do controlador de visualização.

insira a descrição da imagem aqui

Adicionar uma visualização de conteúdo

Adicione a UIViewcomo uma subview à exibição de rolagem. Isso é fundamental. Não tente adicionar muitas subvisões à exibição de rolagem. Basta adicionar um único UIView. Essa será sua visualização de conteúdo para as outras visualizações que você deseja rolar. Coloque a visualização de conteúdo na visualização de rolagem nos quatro lados.

insira a descrição da imagem aqui

Equal Heights

Agora, no Resumo do documento, Commandclique na exibição de conteúdo e na exibição pai da exibição de rolagem para selecionar os dois. Em seguida, defina as alturas como iguais ( Controlarraste da Visualização de conteúdo para a Visualização de rolagem). Isso também é fundamental. Como estamos rolando horizontalmente, a exibição do conteúdo da visualização de rolagem não saberá quão alto deve ser, a menos que a definamos dessa maneira.

insira a descrição da imagem aqui

Nota:

  • Se estivéssemos fazendo o conteúdo rolar verticalmente, definiríamos a largura da exibição de conteúdo como igual à largura do pai da exibição de rolagem.

Adicionar conteúdo

Adicione três se UIViewdê todas as restrições. Eu usei margens de 8 pontos para tudo.

insira a descrição da imagem aqui

Restrições:

  • Vista verde: fixe as bordas superior, esquerda e inferior. Faça a largura 400.
  • Visão em vermelho: fixe as bordas superior, esquerda e inferior. Faça a largura 300.
  • Vista roxa: fixe todas as quatro arestas. Faça a largura seja qual for o espaço restante (268 neste caso).

Definir as restrições de largura também é essencial para que a visualização de rolagem saiba qual será a largura da visualização de conteúdo.

Acabado

Isso é tudo. Você pode executar seu projeto agora. Ele deve se comportar como a imagem de rolagem na parte superior desta resposta.

Para rolagem vertical, basta trocar todas as direções de largura e altura neste exemplo (testado e funcionando).

Um estudo mais aprofundado

Suragch
fonte
9

O contentSize é definido implicitamente aplicando as restrições dentro do UIScrollView.

Por exemplo, se você tem um UIScrollView dentro de um UIView, ele ficará assim (como eu tenho certeza que você sabe):

    UIView *containerView               = [[UIView alloc] init];
    UIScrollView *scrollView            = [[UIScrollView alloc] init];
    [containerView addSubview:scrollView];
    containerView.translatesAutoresizingMaskIntoConstraints = NO;
    scrollView.translatesAutoresizingMaskIntoConstraints    = NO;
    NSDictionary *viewsDictionary       = NSDictionaryOfVariableBindings(containerView, scrollView);

    [containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView]|"
                                                                          options:kNilOptions
                                                                          metrics:nil
                                                                            views:viewsDictionary]];
    [containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|"
                                                                          options:kNilOptions
                                                                          metrics:nil

Isso definirá o scrollView para preencher o tamanho do containerView (para que o containerView precise ter um determinado tamanho).

Em seguida, você pode ajustar o contentSize do UIScrollView configurando-o implicitamente para ser grande o suficiente para manter os botões como este:

    UIButton *buttonA                   = [[UIButton alloc] init];
    UIButton *buttonB                   = [[UIButton alloc] init];
    UIButton *buttonC                   = [[UIButton alloc] init];
    [scrollView addSubview:buttonA];
    [scrollView addSubview:buttonB];
    [scrollView addSubview:buttonC];
    buttonA.translatesAutoresizingMaskIntoConstraints       = NO;
    buttonB.translatesAutoresizingMaskIntoConstraints       = NO;
    buttonC.translatesAutoresizingMaskIntoConstraints       = NO;

    viewsDictionary                     = NSDictionaryOfVariableBindings(scrollView, buttonA, buttonB, buttonC);

    [scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[buttonA]-|"
                                                                       options:kNilOptions
                                                                       metrics:nil
                                                                         views:viewsDictionary]];
    [scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[buttonA]-[buttonB]-[buttonC]-|"
                                                                       options:NSLayoutFormatAlignAllBaseline
                                                                       metrics:nil
                                                                         views:viewsDictionary]];
Infinity James
fonte
Então, defino as restrições entre o scrollView e os botões, e não o containerView e os botões? Acho que essa é a única diferença que estou usando entre o seu código e o que estou fazendo via storyboard agora.
user1459524
Após a segunda leitura, só percebi que você está configurando uma visualização CONTAINER e não uma visualização CONTENT. Com base no seu código, recriei tudo exatamente no storyboard, e ele não está rolando. Vou editar minha pergunta com algumas capturas de tela.
user1459524
1
Portanto, minha tentativa de recriar o código no storyboard não estava 100% correta. O valor à direita do último botão deve ser exatamente zero, espelhando H: | - [botãoA] - [botãoB] - [botãoC] - | o que não é muito óbvio quando se trabalha no storyboard (ou pelo menos não era para mim), mas agora o fato parece trivial. Eu amo o autolayout, mas essas coisinhas te entendem ... #
456131
O que o usuário1459524 mencionado foi um problema para mim. Minha visão inferior era um botão e a restrição inferior era -32 pelo IB. Eu defino isso como 0 e ele atualizou no IB como Bottom Space para: superview. Vai funcionar, também parece, enquanto você está do lado positivo que funciona. Parece que isso pode ser um bug do IB. Espero que ajude alguém. Também removi todas as visualizações e religuei, o que ajuda a tentar descrevê-las e acho que geralmente não leva muito tempo.
Michael Michael
8

Existem muitas perguntas sobre o uso do AutoLayout com o UIScrollView, o ponto principal que ignoramos é que as visualizações internas do UIScrollView fazem restrições contra a Visualização de conteúdo, mas não o próprio UIScrollView. Consulte a Nota técnica TN2154 , você pode encontrar:

A classe UIScrollView rola seu conteúdo alterando a origem de seus limites. Para que isso funcione com o Layout automático, as bordas superior, esquerda, inferior e direita de uma exibição de rolagem agora significam as bordas de sua exibição de conteúdo.

A figura a seguir mostra que: insira a descrição da imagem aqui

Você pode descobrir que o espaço à direita é de 500 pontos; se a restrição for feita no UIScrollView, a visualização será perdida e deve ser atualizada seu quadro. No entanto, sem avisos e sem erros. Porque todas as restrições são contra a exibição do conteúdo.

O UIScrollView calculará o tamanho da visualização do conteúdo de acordo com as restrições das visualizações internas. (Por exemplo, o tamanho do conteúdo: width = 100 (espaço à esquerda) + 200 (largura da visualização) + 500 (espaço à direita), altura = 131 (espaçamento superior) + 200 (altura) + 269 (espaçamento inferior)

Como adicionar restrições para visualizações no UIScrollView:

  1. Criação de imagens das posições das visualizações na exibição de conteúdo.
  2. Adicione espaçamento superior, direito, inferior e esquerdo às bordas da visualização de conteúdo, além da largura e altura dessas visualizações.

E tudo está feito.

Uma maneira fácil de lidar com o AutoLayout com scrollview é adicionar uma exibição de contêiner contendo todas as subvisões na exibição de rolagem.

Conclusão: o ponto principal para entender o AutoLayout com o UIScrollView é que as visualizações internas fazem restrições à exibição de conteúdo, mas não o próprio UIScrollView.

código de exemplo anexado

Danyun Liu
fonte
5

A seguinte solução funcionou para mim no scrollView com autolayout e sem contentSize :

  1. Arraste e solte um scrollView para visualizar o Controlador e aplique quaisquer restrições para cobrir o espaço desejado.
  2. Arraste e solte um UIView dentro do scrollView e faça com que cubra todo o espaço do scrollView e aplique restrições ao espaço superior, esquerdo, direito e inferior do scrollView.
  3. Defina a altura (e largura, se for necessária rolagem horizontal) da vista interna conforme a necessidade de rolagem. Esta parte também pode ser feita a partir do código, se necessário.
  4. Crítico . Depois de definir a altura para algum valor grande no ponto (3), volte ao ponto (2) e certifique-se de definir os valores superior, esquerdo, direito e inferior de volta a zero, pois o Xcode pode ter alterado para você quando você força mudou a altura em (3).

E você terminou. Agora, você pode adicionar qualquer número de controles a essa exibição e aplicar as restrições relevantes uma para a outra (que não parecem funcionar sem essa exibição). Se você não quiser usar essa exibição, precisará aplicar restrições para cada controle relacionado ao scrollView (não relacionado um ao outro).


A dica esmagadora ..............

Crítico . Digamos, com clareza, que o UIScrollView tem 1000 de largura e 100 de altura. (De fato, normalmente esses valores seriam dinâmicos, é claro, dependendo da largura do dispositivo, etc. Mas, por enquanto, basta dizer 1000 de largura e 100 de altura.) Digamos que você esteja fazendo uma rolagem horizontal. Então coloque uma UIView dentro do UIScrollView. (Essa é a "exibição de conteúdo".) Defina todas as quatro restrições da exibição de conteúdo superior, inferior, inicial, final, para a exibição de rolagem. Faça todos zero, mesmo que isso pareça errado. Defina a altura do conteúdo do UIView como 100 e esqueça isso. Agora: você deseja rolar horizontalmente, então defina a largura da exibição do conteúdo como, digamos, 1225.

Observe que a largura da visualização de conteúdo agora é 225 maior que a largura da visualização de rolagem pai. Tudo bem: na verdade, você DEVE fazer isso. Observe que

... você NÃO define a largura à direita como 225 negativo ...

você pensaria que tinha que "combinar" as larguras como faria normalmente . Mas se você fizer isso, não funcionará.

Você deve definir os números iniciais e finais como ZERO , nunca negativos (mesmo que a largura seja "maior")

Curiosamente, você pode realmente definir os números iniciais / finais com qualquer valor positivo (tente dizer "50") e isso fornece uma margem de rejeição. (Muitas vezes, parece ótimo: experimente.) Qualquer valor negativo em ambos os lados será "interrompido silenciosamente".

Observe que, irritantemente, geralmente o Xcode (a partir de 7.3.1 de qualquer maneira),

'definirá' com presteza esses valores para números negativos!

porque tenta contabilizá-los automaticamente para você. Nesse caso, ele se romperá silenciosamente. Defina todos os quatro valores como zero na primeira instância. E defina a largura da exibição do conteúdo muito maior que a "1000" no exemplo.


Editado: acabei usando o UITableView em vez do UIScrollView para a maioria dos meus requisitos. Como tableView me parece muito mais flexível e dinâmico.

zeeawan
fonte
Esta é realmente a melhor resposta aqui. Obrigado!
Fattie
4

Presumo que você esteja tendo problemas com o contentSize. Confira esta postagem no blog sobre como lidar com o contentSizeuso de uma abordagem de AutoLayout "pura". A essência disso é que suas restrições definem implicitamente o tamanho do conteúdo. NUNCA o defina explicitamente ao usar o AutoLayout. Anexei um projeto de exemplo no final da postagem do blog para demonstrar como ele funciona

Edward Huynh
fonte
3

Há uma parte nas notas técnicas que você pode ter examinado. Você pode definir implicitamente o tamanho do conteúdo de uma exibição de rolagem usando restrições fixadas nas bordas da exibição de rolagem.

Aqui está um exemplo simples. Crie um storyboard com uma vista que tenha uma vista de rolagem. Defina as restrições das visualizações de rolagem para ajustá-las ao tamanho da visualização em que você as inseriu.

Dentro dessa visualização de rolagem, adicione uma única visualização. Defina explicitamente o tamanho dessa exibição usando restrições (e verifique se o tamanho é maior que a exibição de rolagem).

Agora, adicione mais quatro restrições à vista interna, bloqueando as quatro arestas da vista interna em sua vista de rolagem pai. Essas quatro restrições farão com que o tamanho do conteúdo se expanda para acomodar a visualização interna.

Se você tiver várias visualizações que deseja adicionar a uma visualização de rolagem, por exemplo, dispostas horizontalmente, bloqueie o lado esquerdo da primeira subvisão à esquerda da visualização de rolagem, bloqueie as sub-visualizações horizontalmente e a direita lado da última subvisualização ao lado direito da visualização de rolagem. Essas restrições forçariam o tamanho do conteúdo da exibição de rolagem a se expandir para acomodar todas as subvisões e suas restrições.

Travis
fonte
3

Se sua pergunta for "Como coloco um monte de UITextFields em um UIScrollView de rolagem vertical, de forma que eles se afastem do caminho do teclado quando estão focados", a melhor resposta é:

Não.

Use um UITableViewController com células estáticas.

Você obtém esse comportamento de rolagem fora do caminho gratuitamente, E todos os inserções de conteúdo Apenas funcionam se o seu controlador de exibição for exibido dentro de um UINavigationController.

Robert Atkins
fonte
3

Você deve organizar seu layout como este
ViewControllerViewcontém ScrollView, ScrollViewcontém ContainerView, ContainerViewcontém 2Labels
insira a descrição da imagem aqui

Em seguida, siga 3 etapas para fazer a ScrollViewrolagem da lata

  1. Definir o ScrollViewpino (superior / direito / inferior / esquerdo) paraViewControllerView
    • Definir o ContainerViewpino (superior / direito / inferior / esquerdo) paraScrollView
    • Definir Horizontally in Container( não definir Vertically in Container)
    • Label1pino ( superior / direita / esquerda) paraContainerView
    • Label1pino (direita / esquerda / inferior ) para ContainerViewe de cima paraLabel1

insira a descrição da imagem aqui

AQUI é o projeto de demonstração

Espero que esta ajuda

Phan Van Linh
fonte
1

A abordagem de autolayout puro funciona perfeitamente, mas é muito difícil configurar se você estiver migrando de um não-autolayout. Já fiz isso algumas vezes e tenho algumas dicas gerais:

  • Comece pequeno: mesmo que isso signifique recriar as visualizações do storyboard, comece com apenas alguns elementos e desenvolva as visualizações lentamente, testando se a rolagem funciona após adicionar alguns elementos.
  • Desative translatesAutoresizingMaskIntoConstraints em tudo: essa sempre foi a causa de conflitos de restrição para mim.
  • Defina as restrições do UIScrollView corretamente: verifique se a visualização de rolagem está conectada de todos os lados à visualização pai, caso contrário, ela não será expandida.
usuario
fonte
1

Depois de algum tempo lidando com esse problema, finalmente encontrei uma solução. Estou trabalhando com storyboards de tamanhos de classe universais (600x600). Criei um UIView (contentView) do tamanho do scrollView e criei restrições para Superior, Inferior, Principal e Final no scrollView. Depois, recortei manualmente o tamanho do contentView para 600x600. O storyboard parou de tentar redimensionar tudo e eu pude trabalhar, mas a vista parecia horrível no dispositivo ou simulador real. Fiz 2 tomadas de restrição com esses tamanhos cortados.

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *contentViewWidthConstraint; 
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *contentViewHeightConstraint;

Em seguida, em viewDidLoad

CGSize viewSize = self.view.frame.size;
self.contentViewWidthConstraint.constant = viewSize.width;
self.contentViewHeightConstraint.constant = viewSize.height;

Funciona bem.

Cristian Pena
fonte
1

Passei dias tentando encontrar uma solução de como usar o AutoLayout para exibir um Scrollview incorporado, para centralizar o scrollview na tela visível, que funciona em todos os dispositivos / dimensões da tela e também na rotação da tela.

Passei dias tentando fazer isso apenas com o Autolayout e cheguei perto, mas nunca perto o suficiente. Então, no final, eu tive que adicionar 3 linhas de código por tela também, no viewDidLoad.

Veja a solução abaixo:

  1. Crie a visualização de rolagem e preencha-a com os objetos que você deseja
  2. Ativar layout automático
  3. Em seguida, centralize o ScrollView na vertical e na horizontal Center ScrollView
  4. Selecione a visualização e, em seguida, 'Adicionar restrições ausentes' - isso funciona
  5. O resultado é que muitas restrições são geradas. Existem dois novos criados para a visualização: 'Horiz space scrollview to View' e 'Vert space scrollview to view' ou vice-versa.
  6. Exclua o 'Horiz space scrollview para View' para ficar com 3 restrições na View. Os 2 para inserir a vista de rolagem na vista e aquele para definir um espaço vertical entre a vista de rolagem e a vista
  7. Agora, vincule a restrição Vert ao seu código clicando e Ctrl arrastando-o para o arquivo de cabeçalho e criando um NSLayoutConstraint IBOutlet (eu chamei mine constraintVertVtoSV)
  8. Agora vá para o arquivo .m e adicione essas linhas de código no viewDidLoad (brinque com a quantidade de preenchimento para obter a centragem correta do vert)

    if (IPAD)

    {self.constraintVertVtoSV.constant = 150.0; }

  9. agora isso deve ser executado em todos os dispositivos e estar centralizado corretamente e ainda rolar corretamente.

Cara
fonte
1

Se como eu, basta usar conteúdo estático sem restrições dentro da subvisão, como você pode fazer assim:

override func viewDidLayoutSubviews() {
    scrollView.contentSize = CGSizeMake(320, 800)
}
Antzi
fonte
1

Problema semelhante que estou tendo hoje com o iOS 8.4, Xcode 6.4

Existe uma exibição que contém uma exibição de rolagem, contendo um contentView (UIView) contendo sub-visualizações.

Tudo é layout automático em qualquer lugar. As arestas da vista de rolagem são fixadas nas arestas das vistas pai com restrições. As arestas da exibição de conteúdo são fixadas nas arestas da exibição de rolagem com restrições.

Originalmente, a exibição de conteúdo se recusava a dimensionar como a largura total da exibição de rolagem. Eu tive que adicionar uma restrição adicional na exibição de conteúdo para que sua largura correspondesse à exibição de rolagem pai. Ou eu poderia definir uma restrição contentView.centerX == scrollView.centerX. Qualquer um desses, além de fixar as bordas, de repente fez o tamanho da exibição do conteúdo corretamente.

// Either one of these additional constraints are required to get autolayout to correctly layout the contentView. Otherwise contentView size is its minimum required size
scrollView.addConstraint(NSLayoutConstraint(item: contentView, attribute: .CenterX, relatedBy: .Equal, toItem: scrollView, attribute: .CenterX, multiplier: 1.0, constant: 0))
scrollView.addConstraint(NSLayoutConstraint(item: contentView, attribute: NSLayoutAttribute.Width, relatedBy: .Equal, toItem: scrollView, attribute: .Width, multiplier: 1.0, constant: 0.0))

Fixar as bordas da visualização de conteúdo na visualização de rolagem usando restrições visuais do formulário,

let cvConstraints = ["H:|[contentView]|", "V:|[contentView]|"]

Eu uso uma rotina para percorrer a matriz e adicioná-los ao scrollView.

David
fonte
1

Eu enfrentei um problema semelhante. Eu defini todas as restrições e sempre me perguntei por que ela ainda redimensiona algumas subvisões. Minha solução foi definir clipsToBounds como YES.

i89
fonte
1

Em breve você pode usar esta solução de trabalho.

Restrições

ScrollView: À esquerda, à direita, superior, inferior = visão geral

ContentView: À esquerda, à direita, superior, inferior = ScrollView. Altura fixa / relativa ao conteúdo.

É possível definir a restrição de largura (contentView) como igual à superview de visualizações de rolagem, mas selecione remover remover no tempo de construção, porque você adicionará essa restrição programaticamente. Isso é apenas para que o IB não reclame com avisos.

extension UIView {

    func setupContentViewForViewWithScroll(contentView vwContent : UIView) {
        //Set constraint for scrollview content
        let constraint = NSLayoutConstraint(item: vwContent, attribute: NSLayoutAttribute.Width, relatedBy: .Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: self.bounds.size.width)
        vwContent.addConstraint(constraint)
        self.layoutSubviews()
    }

}

E no View Controller viewDidLayoutSubviewseu chamo este método:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    self.view.setupContentViewForViewWithScroll(contentView: vwContent)
}
Ibrahim Yildirim
fonte
0

Sei que esta é uma solução para leigos e não o que a Apple sugere na documentação, mas funcionou duas vezes para mim, com conteúdo diferente e pode ser configurada rapidamente: No controlador de exibição de storyboard, insira o UIView. No UIView, insira uma Visualização de tabela, Dinâmica, 0 protótipo de células, Estilo simples ou Agrupado. Na exibição de tabela, insira uma exibição de rolagem; na exibição de rolagem, insira o conteúdo. É isso, não há configurações no controlador de exibição personalizado.

Rinaldo
fonte