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.