O UIScrollView não está rolando


128

Eu tenho um UIScrollViewque contém muitos UIImageViews, UILabels, etc ... os rótulos são muito mais longos que o UIScrollView, mas quando executo o aplicativo, não consigo clicar e rolar para baixo ...

Por que isso pode ser?

obrigado


New 2013/03/26 eu tropecei em uma maneira mais fácil de fazer isso sem código (configuração contentSize) stackoverflow.com/a/15649607/1705353
Dickey Singh

Respostas:


169

É sempre bom mostrar um trecho completo de código de trabalho:

// in viewDidLoad (if using Autolayout check note below):

UIScrollView *myScrollView;
UIView *contentView;
// scrollview won't scroll unless content size explicitly set

[myScrollView addSubview:contentView];//if the contentView is not already inside your scrollview in your xib/StoryBoard doc

myScrollView.contentSize = contentView.frame.size; //sets ScrollView content size

Swift 4.0

let myScrollView
let contentView

// scrollview won't scroll unless content size explicitly set

myScrollView.addSubview(contentView)//if the contentView is not already inside your scrollview in your xib/StoryBoard doc

myScrollView.contentSize = contentView.frame.size //sets ScrollView content size

Não encontrei uma maneira de definir contentSize no IB (a partir do Xcode 5.0) .

Nota: Se você estiver usando o Autolayout, o melhor local para colocar esse código é dentro do -(void)viewDidLayoutSubviewsmétodo.


12
Não se esqueça de definir myScrollView.delegate = selfTAMBÉM, se isso ainda não estiver funcionando, a resposta abaixo tem ótimos conselhos (vá para o seu xib / StoryBoard e verifique se o "AutoLayout" está desativado). Dica profissional: Você também pode incluir <UIScrollViewDelegate>no seu arquivo .h se desejar fazer coisas como rolar programaticamente seu UIScrollView.
Albert Renshaw

1
@ AlbertRenshaw, você deveria ter adicionado uma resposta para que eu pudesse lhe dar um +1 :) O AutoLayout foi o problema comigo .... me deixou louco por 4 horas.
logixologist é o nome do arquivo

2
Colocar código viewDidLayoutSubviewsfez funcionar para mim.
Amr Lotfy 5/05

Para mim, o problema era que ele não precisava rolar, pois tudo se encaixava na tela.
Daniel Springer

122

Se você não puder rolar a exibição mesmo depois de definir o contentSize corretamente, desmarque a opção "Usar AutoLayout" em Interface Builder -> File Inspector.


164
Como alternativa, você pode definir contentSize em viewDidLayoutSubviews: e será aplicado após a conclusão do autolayout.
precisa

2
@ "Chris Vasselli" slove my issue .. GR8 .. :-) #
Ayaz

3
O comentário de Chris deve ser uma resposta separada!
Ninjaneer 26/05

1
Muito obrigado Chris Vasselli! Com o Auto Layout ativado, ele não funciona em viewDidLoad, mas em viewDidLayoutSubviews!
Romain

1
Woah, eu nunca notei todos esses comentários antes! Ainda bem que pude ajudar muitos de vocês! Acabei de publicar uma resposta separada, por isso espero que seja mais fácil de encontrar.
22414 Chris Chasselli

68

Você precisa definir a contentSizepropriedade da exibição de rolagem para que ela role corretamente.

Se você estiver usando autolayout, você precisa conjunto contentSizeno viewDidLayoutSubviewsfim para que possa ser aplicada depois da conclusão do autolayout.

O código pode ficar assim:

-(void)viewDidLayoutSubviews
{
    // The scrollview needs to know the content size for it to work correctly
    self.scrollView.contentSize = CGSizeMake(
        self.scrollContent.frame.size.width,
        self.scrollContent.frame.size.height + 300
    );
}

Agradecemos uma tonelada. Isso funcionou porque, por algum motivo, mesmo quando eu defini o valor contentSizecomo contentView, o tamanho de scrollView e contentView parece ser definido da mesma forma. Mas definir altura de contentSizepara um valor maior que a altura de contentView, funcionou.
Skywalker

viewDidLayoutSubviewspode ser chamado várias vezes durante um ciclo de vida, para que você corra o risco de aumentar a altura maior que o esperado.
Anon_nerd 04/09/19

@anon_nerd basta verificar se já foi chamado e apenas adicionar altura, se não for o caso
Daniel Springer

45

A resposta acima está correta - para fazer a rolagem acontecer, é necessário definir o tamanho do conteúdo.

Se você estiver usando o construtor de interface, uma maneira elegante de fazer isso é com atributos de tempo de execução definidos pelo usuário. Por exemplo:

insira a descrição da imagem aqui


isso não fez nada por mim.
precisa

4
Ops, a imagem mostra {0, 0}, mas é claro que você precisa inserir números grandes o suficiente. . essa abordagem funcionará apenas para visualizações simples, onde você conhece o tamanho do conteúdo antecipadamente. . . (de fato, para visualizações complexas, recomendo o código puro, de qualquer maneira).
Jasper azuis

Muito menos hacky do que fazê-lo programaticamente. Obrigado!
Jake Stoeffler

1
@JakeStoeffler welcome! :) Ao usar o IB, eu gosto de manter toda a configuração lá (não fragmentada). Mas quando as coisas ficam complexas (widgets de exibição reutilizáveis; adaptadores de modelo, manipulações de camada; CAAnimations etc.), eu prefiro visualizações totalmente programáticas. . . mais fluente.
Jasper Blues

Eu tentei isso, funciona quando a exibição aparece, mas, na alteração de orientação, o contentSize definido na tela acima é ignorado e meu log diz que o contentSize está com 0,0. Alguma idéia de como consertar isso?
Shoogle 28/03

40

Tente redimensionar o tamanho do conteúdo para grandes números. Eu não conseguia entender por que minha exibição de rolagem não rola mesmo quando o tamanho do conteúdo parece ser maior que o tamanho do controle. Descobri que, se o tamanho do conteúdo for menor que o necessário, ele também não funcionará.

self.scrollView.contentSize = CGSizeMake(2000, 2000);

Em vez de 2000, você pode colocar seus próprios números grandes. E se funcionar, significa que o tamanho do seu conteúdo não é grande o suficiente quando você redimensiona.

O delegado não é necessário para que a exibição de rolagem funcione.


2
Gênio - uma maneira simples de verificar o que está acontecendo. Muitíssimo obrigado!
The Crazy Chimp

13

Verifique se a propriedade contentSize da exibição de rolagem está definida para o tamanho correto (por exemplo, uma grande o suficiente para abranger todo o seu conteúdo).


1
eu tenho que fazer isso programaticamente? ou posso fazer isso no IB?
Mark

Se você estiver usando o IB, poderá configurá-lo a partir daí - veja abaixo. . (Resposta separada, para que eu possa incluir fotos).
Jasper azuis

7

Desmarque a opção 'Usar Autolayout'.

Ambiente: xCode 5.0.2 Storyboards ios7


5

No meu caso, eu tive que definir delaysContentTouchescomo true porque os objetos dentro do scrollView estavam todos capturando os eventos de toque e se manipulando, em vez de permitir que o próprio scrollView o tratasse.


Eu tenho o mesmo problema. O problema para mim é que, ao transformar atrasosContentTouches em true, você terminará com desenhos de qualidade inferior com um lápis de maçã. Mas este é um caso extremo :) na maioria dos casos, resolver o problema
Romone

4

Defina a contentSizepropriedade UIScrollviewno ViewDidLayoutSubviewsmétodo Algo assim

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    scrollView.contentSize = CGSizeMake(view.frame.size.width, view.frame.size.height)
}

3

A idéia de por que a exibição de rolagem não está rolando porque você define o tamanho do conteúdo para rolagem menor que o tamanho da exibição de rolagem, o que está errado. Você deve definir o tamanho do conteúdo maior que o tamanho da sua exibição de rolagem para navegar através dele durante a rolagem.

A mesma idéia com o zoom, você define os valores mínimo e máximo para o zoom, que serão aplicados por meio da ação de zoom.

bem-vinda :)


3

Uma pequena adição, todas as opções acima, são as reais razões pelas quais sua visualização de rolagem pode não estar rolando, mas às vezes irracionalmente esse pode ser o motivo, especialmente quando a visualização de rolagem é adicionada por meio do código e não do IB, você pode ter adicionado suas subvisões à visualização pai e não para o scrollview faz com que o subview não role

e mantenha o tamanho do conteúdo definido e maior que o quadro de visualização principal (duhh !!)


3

Eu fiz funcionar na minha primeira tentativa. Com layout automático e tudo, sem código adicional. Em seguida, uma exibição de coleção foi banal, travando em tempo de execução, não consegui encontrar o que estava errado, então excluí e recriei (estou usando o Xcode 10 Beta 4. Parecia um bug) e a rolagem desapareceu. A exibição de coleção funcionou novamente!

Muitas horas depois .. foi isso que o corrigiu para mim. Eu tinha o seguinte layout:

UIView

  • Área segura
  • Visualização de rolagem
    • Visualização de conteúdo

Está tudo nas restrições. Área segura é automaticamente definida pelo sistema. Na pior das hipóteses, remova todas as restrições para as visualizações de rolagem e conteúdo e não tenha IB redefinindo / criando-as para você. Faça-os manualmente, ele funciona.

  • Para a visualização Rolagem, fiz: Alinhar Trailing / Top à Área Segura. Largura / altura iguais à área segura .
  • Para a visualização Conteúdo, fiz: Alinhar Trailing / Leading / Top / Bottom à Superview (a visualização de rolagem)

basicamente, o conceito é fazer com que a visualização de conteúdo seja adequada ao Scrollview, que é adequado à Área segura.

Mas, como tal, não funcionou. A exibição de conteúdo perdeu a altura. Eu tentei tudo o que pude e o único que fez o truque foi uma altura de exibição de conteúdo criada, criando a exibição de conteúdo com controle de arrastar ... para si mesma . Isso definiu uma altura fixa, cujo valor foi calculado a partir do tamanho do controlador de exibição (definido como forma livre, mais longa que a tela real, para conter todas as minhas subvisões) e, finalmente, funcionou novamente!


Você é muito bem-vindo! Eu sei exatamente como você se sentiu .. ;-)
Michele Dall'Agata

Thaaaaks, passei muitas horas e isso resolveu o meu problema
Andoni Da Silva

3

Se você estiver recebendo uma mensagem (IOS8 / swift) que viewDidLayoutSubviewsnão existe, use o seguinte

override func viewDidAppear(animated: Bool)

Isso corrigiu para mim


2

Algo que não foi mencionado antes!

Verifique se a tomada estava conectada corretamente ao scrollView! Ele deve ter um círculo preenchido, mas mesmo se você tiver preenchido um círculo, o scrollView pode não estar conectado - verifique novamente! Passe o mouse sobre o círculo e veja se a visualização de rolagem real é destacada! (Este foi um caso para mim)

//Connect below well to the scrollView in the storyBoard
@property (weak, nonatomic) IBOutlet UIScrollView *scrollView;

2

Muitas vezes o código está correto se você seguiu um tutorial, mas o que muitos iniciantes não sabem é que o scrollView NÃO vai rolar normalmente pelo simulador. Supõe-se rolar apenas quando você pressiona o mouse e simultaneamente rola. Muitos usuários experientes de XCode / Swift / Obj-C estão acostumados a fazer isso e não sabem como isso poderia ser ignorado pelos iniciantes. Tchau :-)

@IBOutlet weak var scrollView: UIScrollView!
override func viewDidLoad() {
    super.viewDidLoad()
    view.addSubview(scrollView)
    // Do any additional setup after the view
}

override func viewWillLayoutSubviews(){
    super.viewWillLayoutSubviews()
    scrollView.contentSize = CGSize(width: 375, height: 800)
}

Esse código funcionará perfeitamente bem desde que você faça o que eu disse acima


1

Se nenhuma das outras soluções funcionar para você, verifique duas vezes se a visualização de rolagem é realmente UIScrollViewno Interface Builder.

Em algum momento dos últimos dias, meu UIScrollView tipo mudou espontaneamente para a UIView, embora sua classe dissesse UIScrollViewno inspetor. Estou usando Xcode 5.1 (5B130a).

Você pode criar uma nova visualização de rolagem e copiar as medidas, configurações e restrições da visualização antiga ou alterar manualmente sua visualização para uma UIScrollViewno xibarquivo. Fiz uma comparação e encontrei as seguintes diferenças:

Original:

<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" directionalLockEnabled="YES" bounces="NO" pagingEnabled="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Wsk-WB-LMH">
...
</scrollView>

Após o tipo alterado espontaneamente:

<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" customClass="UIScrollView" id="qRn-TP-cXd">
...
</view>

Então substituí a <view>linha pela minha <scrollView>linha original .

Também substitui a tag de fechamento da exibição </view>por </scrollView>.

Certifique-se de manter o ID igual à visualização atual, neste caso: id = "qRn-TP-cXd".

Eu também tive que liberar o xib do cache do Xcode excluindo os dados derivados do aplicativo:

  • Xcode->Window->Organizer->Projects, escolha seu projeto, na linha Dados Derivados, clique em Excluir ...

Ou se estiver usando um dispositivo:

  • Xcode->Window->Organizer->Device, escolha seu dispositivo-> Aplicativos, escolha seu aplicativo, clique em (-)

Agora limpe o projeto e remova o aplicativo do simulador / dispositivo:

  • Xcode->Product->Clean
  • iOS Simulator/device->presse mantenha pressionado o app->click(X) para removê-lo

Você poderá criar e executar seu aplicativo e ter a funcionalidade de rolagem novamente.

PS: Não precisei definir o tamanho do conteúdo da exibição de rolagem viewDidLayoutSubviewsou desativar o layout automático, mas YMMV.


1

Se você scrollViewé uma sub-visualização de containerViewalgum tipo, verifique se scrollViewestá dentro do quadro ou dos limites do containerView. Eu tinha o containerView.clipsToBounds = NOque ainda me permitia ver o scrollView, mas porque scrollViewnão estava dentro dos limites containerViewdele, não detectava eventos de toque.

Por exemplo:

containerView.frame = CGRectMake(0, 0, 200, 200);
scrollView.frame = CGRectMake(0, 200, 200, 200);
[containerView addSubview:scrollView];
scrollView.userInteractionEnabled = YES;

Você poderá ver o scrollView, mas ele não receberá interações do usuário.


1

adicionar o código a seguir viewDidLayoutSubviewsfuncionou para mim com o Autolayout. Depois de tentar todas as respostas:

- (void)viewDidLayoutSubviews
{
    self.activationScrollView.contentSize = CGSizeMake(IPHONE_SCREEN_WIDTH, 620);

}

//set the height of content size as required

1

Adicione UIScrollViewDelegatee adicione o seguinte código ao viewDidAppearmétodo corrigido para mim.

@interface testScrollViewController () <UIScrollViewDelegate>

-(void)viewDidAppear:(BOOL)animated {
    self.scrollView.delegate = self;
    self.scrollView.scrollEnabled = YES;
    self.scrollView.contentSize = CGSizeMake(375, 800);
}

1

Meu problema foi resolvido por:

  1. definindo o contentSize no scrollView para uma altura grande
  2. MAS também tive que corrigir as restrições superior e / ou inferior nas visualizações no scrollView, o que significava que os indicadores de rolagem eram exibidos na tela, mas o conteúdo não rolava

Depois de remover as restrições superior e / ou inferior vinculadas à área segura e / ou à visão geral, as visualizações dentro do scrollView podem rolar novamente e não ficam fixas na parte superior da parte inferior da tela!

Espero que isso pare outra pessoa de horas de dor com esse problema específico.


1

outro caso divertido:

scrollview.superview.userInteractionEnabled deve ser verdadeiro

Eu desperdicei 2 + horas perseguindo isso apenas para descobrir que o pai é UIImageView que, naturalmente, tem userInteractionEnabled == false


0

Depois de falhar com as respostas fornecidas neste tópico, me deparei com este artigo com a solução.

Há duas coisas não intuitivas sobre a configuração da exibição de rolagem com o layout automático:

  1. As restrições que você configura como margem entre a visualização de conteúdo e a visualização de rolagem não influenciam o tamanho da visualização de conteúdo. Eles realmente são margens. E para fazê-lo funcionar, a visualização de conteúdo deve ter um tamanho fixo.
  2. O truque para o tamanho fixo é que você pode definir a largura da visualização de conteúdo igual à do pai da visualização de rolagem. Basta selecionar as duas vistas na árvore à esquerda e adicionar a restrição de larguras iguais.

Esta é a essência desse artigo. Para uma explicação completa, incluindo ilustrações, confira.


@PredragManojlovic Como pode ficar mais geral do que isso? Essa é a única maneira de obter o scrollview para funcionar corretamente, usando o layout automático.
precisa

0

Descobri que, com esse problema de AutoLayout ... se eu apenas fizer o ViewControlleruso em UIViewvez da UIScrollViewclasse ... basta adicionar um UIScrollVieweu ... que funcione.


0

Eu tive o mesmo problema no IB.

Depois de definir o início, o final, o topo e o fundo do scrollView para seu superView. Fiz as seguintes alterações para tornar o containerView rolável, que funcionou.

Para fazer o scrollView rolar apenas na direção horizontal, faça a restrição com scrollView's centerY = ContainerView's centerY

e para torná-lo rolável verticalmente, faça o scrollX's centerX = ContainerView's centerX

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.