como faço para usar UIScrollView no Interface Builder?

95

Embora eu já tenha usado com UIScrollViewsucesso no passado manipulando-o programaticamente, estou tendo problemas para fazer funcionar configurando-o exclusivamente no Interface Builder.

Tenho uma página "sobre" simples no meu aplicativo para iPhone. Ele tem um UITextView, alguns ícones e links para meus outros aplicativos. Eu adicionei todas essas visualizações à minha UIScrollView, organizando-as de forma que seu tamanho total seja> 480. Quando eu inicio meu aplicativo, a visualização de rolagem exibe apenas o conteúdo que cabe na tela e nada rola.

É possível fazer isso inteiramente via IB ou devo manipular o contentSize via código?

George Armhold
fonte

Respostas:

130

Você se esqueceu de definir a propriedade contentSize do UIScrollView. Estranhamente, você não pode fazer isso no Interface Builder. Você terá que fazer isso a partir do controlador de visualização que gerencia esta visualização de rolagem.

Stefan Arentz
fonte
42
Uau, meio que torna o IB bastante inútil ... Isso funcionou, obrigado.
George Armhold
20
Você poderia criar uma subclasse de UIScrollvView que verifica se há apenas uma subvisualização em (0,0) e, a seguir, define automaticamente o contentSize com base nessa subvisualização.
Stefan Arentz
1
Esse é o melhor conselho que recebo há algum tempo. Não consegui descobrir por que minha visualização de rolagem não funcionava e não encontrei essa informação sobre contentSize em nenhum outro lugar. Obrigado.
Drew C
46
Eu estava tentando descobrir como definir contentSize no Interface Builder e encontrei esta discussão. Pelo menos para mim, no Xcode 4.5, posso configurá-lo usando “Atributos de tempo de execução definidos pelo usuário”, adicionando uma entrada chamada contentSizede tipo Sizee configurando o valor desejado.
nlogax,
5
Ainda estou perplexo com relação ao motivo pelo qual o iOS não define automaticamente o contentSizede uma visualização de rolagem com base nas dimensões de suas subvisualizações , pelo menos como o comportamento padrão.
aroth
113

A resposta de Boby_Wan me fez pensar e descobri a seguinte solução para configurar o contentSize do UIScrollView no Interface Builder:

  1. Selecione o UIScrollViewna cena do Storyboard
  2. Vá para o inspetor de identidade , crie um novo Atributo de tempo de execução definido pelo usuário (clique no botão +)
  3. Altere o atributo Key Path paracontentSize
  4. Altere o atributo Tipo paraSize
  5. Agora definir o valor para { width conteúdo desejado , a altura desejada conteúdo }

por exemplo, definir o valor para {320, 920} permitirá que o usuário role para baixo em uma tela extra inteira no iPhone.

(Estou usando o xcode 4.3.3, o iOS Deployment Target do projeto é 5.1)

Quando fiz isso pela primeira vez, recebi o seguinte erro:

Configuração ilegal:
     atributos de tempo de execução definidos pelo usuário de tipo de tamanho com versões do Xcode anteriores a 4.3
     MainStoryboard.storyboard

Se você também obtiver este erro, é simples de corrigir: selecione o Storyboard no Navegador do Projeto e abra o Inspetor de Arquivos . Encontre / expanda a seção Documento do Interface Builder e há um menu suspenso para Desenvolvimento . Certifique-se de que esteja definido comoXcode 4.3

Herr Grumps
fonte
7
Achado incrível! PS: Estou surpreso que isso seja o melhor que a Apple poderia fazer. Acho que isso mostra que mesmo os funcionários da Apple nunca usam sua própria ferramenta (construtor de interface) :).
Adam
Brilhante, isso acabou de funcionar para mim no Xcode 4.4. Mas agora como coloco botões na parte da visualização de rolagem que não consigo "ver" no IB?
Robert Atkins,
1
Acabei de resolver - você precisa soltar o arrasto quando o ponteiro ainda estiver dentro da "tela", caso contrário, ele voltará para quando você começou. Que dor.
Robert Atkins,
Eu tentei dessa forma, mas estou recebendo um erro, "this class is not key value coding-compliant for the key keyPath"por favor, pode me ajudar o que estou fazendo de errado? observe que eu uso xamarin-ios-c #
SoftSan
25

Com o Autolayout (iOS6 +), você pode evitar a configuração contentSize. Em vez disso, defina as seguintes restrições:

  1. Prenda o topo da scrollview no topo de seu filho mais alto.
  2. E prenda a parte inferior na parte inferior de seu filho mais inferior.
Danyal Aytekin
fonte
1
Obrigado - a configuração contentSizenão funciona com Xcode 5 e iOS 7
colincameron
18

Você pode fazer isso usando apenas o Interface Builder, vá para o Inspetor de Identidade (a terceira guia do inspetor) e adicione um novo atributo de Tempo de Execução Definido pelo Usuário com

  • Caminho da chave: contentSize
  • Tipo: Tamanho
  • Valor: {largura, altura}
Anton Banchev
fonte
14

Agora existe uma maneira de fazer um UIScrollViewpergaminho sem sair do Storyboard :

  1. Selecione UIScrollViewno Storyboard, vá para o inspetor Size e altere o valor Bottom (ou qualquer outro valor que você precise alterar) na seção Content Insets para a altura da área de conteúdo.
  2. Agora vá para o inspetor de identidade e crie um novo Atributo de tempo de execução definido pelo usuário (clicando no botão +) e nomeie-o contentSize. Não importa o tipo ou valor que você preenche (você pode até deixar o valor padrão).

Isso fará com que UIScrollViewfuncione bem, embora eu não saiba por que a segunda etapa é necessária (descobri por acaso). :(

RoberRM
fonte
Alterar o valor Bottom para quê?
zakdances
Altere-o para a altura da área de conteúdo. Parece funcionar e substitui o valor fornecido para o atributo "contentSize" definido pelo usuário.
Reid Ellis,
Sim, Reid, você está certo: você deve alterar o valor Bottom para a altura da área de conteúdo. Eu editei minha postagem original para refletir isso. Obrigado!
RoberRM
4

uma abordagem que usei no passado é arrastar a visualização de rolagem para fora de sua visualização no construtor de interface e definir seu tamanho real para o que deseja que o contentSize seja.

o que não é inerentemente óbvio sobre o construtor de interface é que você pode ter visualizações não associadas que são armazenadas na ponta, mas não fazem parte da visualização principal para a qual a ponta se destina.

na visualização onde deseja que a visualização de rolagem fique, coloque um UIView simples, que você usa como um espaço reservado. (isso é simplesmente para que você possa projetar visualmente sua localização. se você estiver apenas usando a visualização inteira, pode pular esta etapa e usar o segundo trecho de código que forneci no final desta resposta).

você pode então preencher a visualização de rolagem com controles, exibindo-a visualmente como você deseja. forneça as propriedades placeholder e scrollview dentro de seu controlador de visualização para que você possa acessá-las em tempo de execução.

em tempo de execução, em - (void) viewDidLoad

scrollView.contentSize = scrollView.frame.size;
scrollView.frame = placeholder.frame;
[placeholder.superview addSubView:scrollView];
[placeholder removeFromSuperview];

alternativamente (se você não usou um marcador de posição):

CGRect f = self.view.frame;
scrollView.contentSize = f.size;
f.origin.x = 0;
f.origin.y = 0;
scrollView.frame = f;
[self.view addSubView:scrollView];

finalmente, se você "perder" sua visualização de rolagem no construtor de interface (é possível fechá-la para que desapareça da grade de design), não entre em pânico. apenas clique nele na lista de objetos à esquerda da grade de design.

não sincronizado
fonte
1
Obrigado - funcionou bem. Também é necessário declarar IBOutlets em YourViewController.h para o espaço reservado e visualizações de rolagem e conectá-los no Interface Builder. E, por último, dot.notation não foi apreciado pelo xCode para a 3ª linha, então usei a sintaxe normal de envio de mensagem - então tudo funcionou muito bem!
jiy
não se preocupe. sempre há o perigo ao postar trechos de código de que algumas pessoas não possam usá-los para entender o conceito, em vez de esperar que o código "exato" funcione em todas as situações.
não sincronizado de
Este é o método que realmente uso. Eu nem preciso redimensionar este programa. Acho que é assim que se pretende fazer. É a única resposta verdadeira.
user4951
Depois de desenhá-lo para fora, vou apenas movê-lo para uma visão geral. Tada.
user4951
Na verdade, comecei a usar o design de algumas visualizações fora de uma cena para rascunhos e isso torna a vida muito mais fácil em algumas situações, mesmo não relacionadas a esta. Obrigado por esta resposta.
Benjamin
4

No Xcode 4.5 usando Autolayout, não tenho a seção Content Insets no meu inspetor de tamanho. Então, tive que adicioná-lo em Atributos de tempo de execução definidos pelo usuário e funcionou bem.

O que você adiciona em "Atributos de tempo de execução definidos pelo usuário" é keyPath == contentInset, que é do tipo "Rect" (UIEdgeInsets, que tem a mesma entrada de um Rect) e é definido como {top, left}, {bottom, right}. O contentSize define apenas a região da janela scrollview. contentInset define a área rolável.

Espero que isso ajude alguém na mesma situação.

Robert Wasmann
fonte
Para UITextView, use "textContainerInset" keyPath
Dima Deplov
4

Muitas das respostas acima são enganosas ou desatualizadas. A partir de 2017 (possivelmente muito antes) o construtor de interface oferece suporte a scrollviews com conteúdo dimensionado automaticamente. O truque é que o XCode dá um significado especial e fora do padrão às restrições entre a visualização da rolagem e o conteúdo dentro dela. Essas restrições "internas" não afetarão realmente o tamanho do conteúdo como você poderia esperar.

Isso significa que você pode, por exemplo, ter seu scrollview fixado na parte inferior da visualização principal com margem zero, e também ter o conteúdo do scrollview fixado na parte inferior da scrollview com margem zero, mas o conteúdo não será realmente esticado por isso. Em vez disso, o conteúdo terá seu tamanho autodeterminado (mais abaixo) e este também será o tamanho da área de rolagem dentro da visualização da rolagem.

Pense nisso assim - há uma assimetria nas restrições de vinculação a um scrollview: Restrições do scrollview ao mundo "externo" (pai) determinam o tamanho e a posição do scrollview como de costume. Mas as restrições "dentro" do scrollview realmente definem o tamanho e a posição da área de rolagem do scrollview, vinculando-a ao conteúdo.

Isso é totalmente não óbvio porque quando você vai definir as restrições, o XCode sempre sugerirá o espaçamento atual e pode nunca ocorrer a você alterar intencionalmente as restrições internas e externas de uma forma que entre em conflito. Mas você pode, e eles têm o significado descrito acima: um controla o layout de scrollview e outro controla o tamanho da área de conteúdo rolável.

Eu tropecei nisso por acidente e, em seguida, vendo como parecia funcionar, me levou a este artigo que explica tudo e cita a fonte de documentos da Apple para isso:

https://spin.atomicobject.com/2014/03/05/uiscrollview-autolayout-ios/

Uma última informação crítica, sobre o tamanho autodeterminado do conteúdo: você pode sentir que está em um beco sem saída aqui porque você normalmente dimensiona seu conteúdo para, por exemplo, a largura da visualização pai, mas neste caso o pai é a visualização em rolagem e conforme descrito acima - a restrição não afetará o tamanho do conteúdo. A resposta aqui é lembrar que você pode restringir itens a itens não diretamente vizinhos em sua hierarquia de visualização: por exemplo, você pode definir a largura de sua visualização de conteúdo para a largura da visualização principal em vez de tentar em vão fazer com que a visualização em rolagem o faça para voce.

Pat Niemeyer
fonte
2

Se você clicar no ícone Propriedades de qualquer View Controller no Interface Builder, você pode defini-lo para um tamanho "Freeform" em Simulated Metrics e alterar o tamanho da View principal para o seu tamanho de conteúdo desejado.

Desta forma, você pode criar o conteúdo do ScrollView como se fosse uma grande exibição. Como é apenas uma métrica simulada, seu View Controller será redimensionado para os limites da janela quando for carregado.

olilândia
fonte
2

Configurar um UIScrollView por meio do Interface Builder não é intuitivo. Aqui está minha lista de verificação para configurá-lo:

  1. Selecione o arquivo XIB do UIViewController. No "Identity Inspector" do construtor de interface, altere o UIView para o tipo de classe UIScrollView

  2. Em "File Inspector", desmarque Autolayout

  3. Em "Attributes Inspector", altere o tamanho para Freeform. Você pode esticar a Visualização de rolagem manualmente ou pode especificar uma largura e altura personalizadas em "Inspetor de tamanho".

  4. Em "Identity Inspector", adicione um novo Atributo de tempo de execução definido pelo usuário chamado "contentSize" do tipo "Size" e altere-o para um valor como {320, 1000}. Você não pode mais definir isso programaticamente e, portanto, precisa desta etapa para que a Visualização de rolagem saiba que o conteúdo da Visualização de rolagem é maior do que a janela.

Maçom livre
fonte
2

Apenas remova o autoLayout em seu scrollview. então o código é tão simples quanto este:

scrollviewName.contentSize = CGSizeMake(0, 650);

basta criar uma propriedade iboulet no arquivo .h e então sintetizar no arquivo .m. Certifique-se de que a rolagem esteja ativada.

Aldrin Equila
fonte
1

Sim, st3fan está certo, a propriedade contentSize de UIScrollView deve ser definida. Mas você não deve desligar o autolayout para essa finalidade. Você pode facilmente configurar contentSize de UIScrollView com autolayout somente em IB, sem qualquer código.

É importante entender que, ao usar autolayout contentSize de UIScrollView, não é definido diretamente, ele é calculado com base nas restrições de todas as subvisualizações de UIScrollView. E tudo que você precisa é fornecer restrições adequadas para subvisualizações para ambas as direções.

Por exemplo, se você tiver apenas uma subvisualização, poderá definir sua altura e espaço de cima para baixo para superview (ou seja, scrollView em nosso caso) contentSize.height é calculado como a soma

Vertical Space (aSubview.top to Superview.top) + aSubview.height + Vertical Space (aSubview.top to Superview.top)

contentSize.width é calculado de forma semelhante a partir de restrições horizontais.

Se houver muito poucas restrições para calcular o contentSize corretamente, um pequeno botão vermelho é mostrado próximo ao item View Controller Scene para informar sobre a ambigüidade do layout.

Se houver muitas subvisualizações, então pode ser uma "cadeia" de restrições: subvisualização superior para superior, alturas e espaços entre subvisualizações e subvisualização inferior para inferior, como na resposta de Danyal Aytekin .

Mas na prática, na maioria dos casos, é mais conveniente apenas adicionar uma visualização vazia com o tamanho necessário e definir os espaços superior, esquerdo, inferior e direito de scrollView como 0. Você pode usar esta visualização como "Visualização de conteúdo", ou seja, colocar todas as outras subvisualizações nela ou se você já tiver muitas subvisualizações e não quiser movê-las e configurar o layout novamente, você pode adicionar esta visão auxiliar às subvisualizações existentes e torná-la oculta.

Para tornar scrollView rolável, o contentSize calculado deve ser maior que o tamanho de scrollView.

Vladimir
fonte
1

Você pode ter UIScrollView no StoryBoard com Autolayouts. Basicamente, o que você precisa é:

  1. Adicionar UIScrollView
  2. Adicione todas as restrições a ele (como inserções das bordas superior, esquerda, direita, inferior)
  3. Adicionar um UIView de 'contêiner' ao UIScrollView
  4. Se você quiser apenas uma rolagem em uma direção (digamos, vertical): defina a altura explicitamente (para a instância, 600) e a largura do link para a largura de UIScrollView.
  5. Se você quiser rolagem bidirecional, defina a largura e a altura.

configuração de storyboard

Eugene Braginets
fonte
0

Aqui está uma solução para projetar ScrollView com um conteúdo maior do que a tela inteiramente no Storyboard (bem, quase inteiramente, você precisará adicionar uma única linha de código também)

https://stackoverflow.com/a/19476991/1869369

Ronny Webers
fonte
0

Eu descobri uma maneira mais conveniente.

1: dimensione o tamanho da visualização de rolagem para conter toda a interface do usuário dentro dela.

2: Adicione um iboutlet da visualização de rolagem.

3: Em viewDidLoad, salve o frame.size da visualização de rolagem.
(por exemplo, _scrollSize = _scrollView.frame.size;)

4: Em viewWillAppear, defina contentSize pelo CGSize que você salvou antes.
(por exemplo, _scrollView.contentSize = _scrollSize;)

5: Concluído ~

Agas
fonte
0
  1. Adicionar UIViewController
  2. Em UIViewController 'Attribute Inspector -> Simulated Metrics' set size Freeform
  3. No UIViewController 'Size Inspector -> View Controller' defina a altura 800
  4. Adicionar UIScrollView em UIViewController
  5. Adicione todas as restrições a UIScrollView (superior, esquerda, direita, inferior) e adicione o alinhamento X = centro
  6. Adicionar UIView em UIScrollView
  7. Adicione todas as restrições ao UIView (superior, esquerda, direita, inferior) e adicione o alinhamento X = centro. Sim, o mesmo que para UIScrollView em # 3, mas para UIView
  8. Adicione restrição de altura ao UIView. Por exemplo 780
  9. Corre

Storyboard

Alexandre
fonte
0

Crie um novo projeto Xcode

Navegue até o arquivo Main.storyboard

Selecione ScrollView na biblioteca de objetos.

Defina o quadro para o ScrollView.

Adicione outra visualização para rolar a visualização e manter o mesmo quadro de ScrollView.

Agora, para definir sua altura e largura dinamicamente, você pode configurar um UIScrollView usando layout automático em XIB

Dilraj Singh
fonte