Eu configurei um ViewPager simples que possui um ImageView com uma altura de 200dp em cada página.
Aqui está o meu pager:
pager = new ViewPager(this);
pager.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
pager.setBackgroundColor(Color.WHITE);
pager.setOnPageChangeListener(listener);
layout.addView(pager);
Apesar da altura definida como wrap_content, o pager sempre preenche a tela, mesmo que a visualização de imagem tenha apenas 200dp. Tentei substituir a altura do pager por "200", mas isso me deu resultados diferentes com várias resoluções. Não consigo adicionar "dp" a esse valor. Como adiciono 200dp ao layout do pager?
Respostas:
Substituir onMeasure do
ViewPager
seguinte modo fará com que ele obtenha a altura do filho maior que ele tem atualmente.fonte
Outra solução mais genérica é começar
wrap_content
a trabalhar.Eu estendi
ViewPager
para substituironMeasure()
. A altura é agrupada em torno da primeira exibição filho. Isso pode levar a resultados inesperados se as visualizações filho não tiverem exatamente a mesma altura. Por isso, a classe pode ser facilmente estendida para, digamos, animar o tamanho da visualização / página atual. Mas eu não precisava disso.Você pode usar este ViewPager em seus layouts XML, exatamente como no ViewPager original:
Vantagem: Essa abordagem permite usar o ViewPager em qualquer layout, incluindo RelativeLayout, para sobrepor outros elementos da interface do usuário.
Uma desvantagem permanece: se você deseja usar margens, é necessário criar dois layouts aninhados e fornecer ao interno as margens desejadas.
Aqui está o código:
fonte
Baseei minha resposta em Daniel López Lacalle e neste post http://www.henning.ms/2013/09/09/viewpager-that-simply-dont-measure-up/ . O problema com a resposta de Daniel é que, em alguns casos, meus filhos tinham altura zero. Infelizmente, a solução foi medir duas vezes.
Isso também permite definir uma altura no ViewPager, se você desejar, ou apenas wrap_content.
fonte
scaleType
e o mesmo,layout_width=match_parent
assim comolayout_height=wrap_content
? há 20dp faltando lá.// super has to be called in the beginning so the child views can be initialized.
<----- Esse era o motivo, tinha que chamá-lo no início e no final da função onMeasure. Yippiii, virtual toca em mim hoje!Eu estava apenas respondendo uma pergunta muito semelhante sobre isso e descobri isso ao procurar um link para fazer backup de minhas reivindicações, que sorte sua :)
Minha outra resposta:
o ViewPager não suporta
wrap_content
, pois (normalmente) nunca possui todos os seus filhos carregados ao mesmo tempo e, portanto, não pode obter um tamanho apropriado (a opção seria ter um pager que muda de tamanho toda vez que você alterna) página).No entanto, você pode definir uma dimensão precisa (por exemplo, 150dp) e também
match_parent
funciona.Você também pode modificar as dimensões dinamicamente a partir de seu código, alterando o
height
-attribute em suaLayoutParams
.Para suas necessidades, você pode criar o ViewPager em seu próprio arquivo xml, com o layout_height definido como 200dp e, em seguida, no seu código, em vez de criar um novo ViewPager do zero, você pode aumentar o arquivo xml:
fonte
layout_height
definido comowrap_content
, mas é ainda pior, pois a solução simples para configurá-lo em um valor fixo não funciona.Usando a resposta de Daniel López Localle , criei esta classe no Kotlin. Espero que você economize mais tempo
fonte
Já enfrentei esse problema em vários projetos e nunca tive uma solução completa. Então, criei um projeto no github WrapContentViewPager como um substituto no local para o ViewPager.
https://github.com/rnevet/WCViewPager
A solução foi inspirada por algumas das respostas aqui, mas aprimora:
Atualizado para a biblioteca de suporte versão 24, que interrompeu a implementação anterior.
fonte
Acabei de esbarrar no mesmo problema. Eu tinha um ViewPager e queria exibir um anúncio no botão dele. A solução que encontrei foi obter o pager em um RelativeView e defini-lo layout_above para o ID da visualização que desejo ver abaixo. isso funcionou para mim.
aqui está o meu XML de layout:
fonte
Eu também tive esse problema, mas no meu caso eu tinha um
FragmentPagerAdapter
que estava fornecendo asViewPager
páginas. O problema que tive foionMeasure()
o deViewPager
chamado antes de qualquer umFragments
deles ter sido criado (e, portanto, não era possível dimensionar-se corretamente).Após algumas tentativas e erros, descobri que o
finishUpdate()
método do FragmentPagerAdapter é chamado após aFragments
inicialização (a partir deinstantiateItem()
noFragmentPagerAdapter
) e também após / durante a rolagem da página. Eu fiz uma pequena interface:que eu passo na minha
FragmentPagerAdapter
e chamo:o que, por sua vez, me permite chamar
setVariableHeight()
minhaCustomViewPager
implementação:Não tenho certeza de que é a melhor abordagem, gostaria de comentar se você acha que é bom / ruim / mau, mas parece estar funcionando muito bem na minha implementação :)
Espero que isto seja útil a alguém!
EDIT: esqueci de adicionar um
requestLayout()
depois de chamarsuper.measure()
(caso contrário, não redesenhar a exibição).Também esqueci de adicionar o preenchimento dos pais à altura final.
Também deixei cair mantendo o MeasureSpecs de largura / altura original em favor da criação de um novo, conforme necessário. Atualizou o código de acordo.
Outro problema que tive foi que ele não se dimensionaria corretamente em um
ScrollView
e descobriu que o culpado estava medindo a criança emMeasureSpec.EXACTLY
vez deMeasureSpec.UNSPECIFIED
. Atualizado para refletir isso.Todas essas alterações foram adicionadas ao código. Você pode verificar o histórico para ver as versões antigas (incorretas), se desejar.
fonte
Outra solução é atualizar a
ViewPager
altura de acordo com a altura da página atualPagerAdapter
. Supondo que você esteja criando suasViewPager
páginas desta maneira:Onde
mPages
uma lista interna dePageInfo
estruturas é adicionada dinamicamente ao métodoPagerAdapter
eCustomImageView
é regularImageView
com oonMeasure()
método de substituição que define sua altura de acordo com a largura especificada e mantém a proporção da imagem.Você pode forçar a
ViewPager
altura nosetPrimaryItem()
método:Observe o
Math.max(height, 1)
. Isso corrige um bug irritante queViewPager
não atualiza a página exibida (mostra em branco), quando a página anterior tem altura zero (ou seja, drawable nulo naCustomImageView
), cada golpe ímpar para frente e para trás entre duas páginas.fonte
item.mImageView.measure(..)
para obter as dimensões corretas nosgetMeasuredXXX()
métodos.Ao usar conteúdo estático dentro do viewpager e você não deseja animação animada, use o seguinte pager de visualização
fonte
fonte
No código-fonte do aplicativo Android do tempo da pipoca, encontrei esta solução que ajusta dinamicamente o tamanho do viewpager com uma bela animação, dependendo do tamanho do filho atual.
https://git.popcorntime.io/popcorntime/android/blob/5934f8d0c8fed39af213af4512272d12d2efb6a6/mobile/src/main/java/pct/droid/widget/WrappingViewPager.java
fonte
Caso você precise do ViewPager que ajuste seu tamanho para cada criança , não apenas para a maior, escrevi um código que faz isso. Observe que não há animação sobre essa alteração (não é necessário no meu caso)
A bandeira android: minHeight também é suportada.
fonte
Melhor resposta de Daniel López Lacalle , reescrita em Kotlin :
fonte
Eu me deparei com o mesmo problema e também tive que fazer com que o ViewPager envolvesse seu conteúdo quando o usuário rolasse entre as páginas. Usando a resposta acima do cybergen, defini o método onMeasure da seguinte maneira:
Dessa forma, o método onMeasure define a altura da página atual exibida pelo ViewPager.
fonte
Nada do sugerido acima funcionou para mim. Meu caso de uso está tendo 4 ViewPagers personalizados
ScrollView
. O topo deles é medido com base na proporção, e o resto apenaslayout_height=wrap_content
. Eu tentei soluções cybergen , Daniel López Lacalle . Nenhum deles funciona totalmente para mim.Meu palpite por que o cybergen não funciona na página> 1 é porque calcula a altura do pager com base na página 1, que fica oculta se você rolar mais.
As sugestões de cybergen e Daniel López Lacalle têm um comportamento estranho no meu caso: 2 de 3 estão carregadas ok e 1 de altura aleatória é 0. Parece que
onMeasure
foi chamado antes das crianças serem preenchidas. Então, eu vim com uma mistura dessas 2 respostas + minhas próprias correções:A idéia é permitir
ViewPager
calcular as dimensões das crianças e salvar a altura calculada da primeira página nos parâmetros de layout daViewPager
. Não se esqueça de definir a altura do layout do fragmento parawrap_content
que você possa obter height = 0. Eu usei este:Observe que esta solução funciona bem se todas as suas páginas tiverem a mesma altura . Caso contrário, você precisará recalcular a
ViewPager
altura com base no filho ativo atual. Não preciso, mas se você sugerir a solução, ficarei feliz em atualizar a resposta.fonte
Para pessoas com esse problema e codificando para Xamarin Android em C #, isso também pode ser uma solução rápida:
Isso é útil principalmente se as visualizações do seu filho tiverem a mesma altura. Caso contrário, você seria obrigado a armazenar algum tipo de valor "minimumHeight" em todos os filhos com os quais você faz check-list e, mesmo assim, talvez não deseje ter espaços vazios visíveis abaixo das visualizações filho menores.
A solução em si não é suficiente para mim, mas isso é porque meus itens filhos são listViews e seu MeasuredHeight não é calculado corretamente, ao que parece.
fonte
Eu tenho uma versão do WrapContentHeightViewPager que estava funcionando corretamente antes da API 23 que redimensionará a base de altura da exibição pai na exibição filho atual selecionada.
Após a atualização para a API 23, ela parou de funcionar. Acontece que a solução antiga estava sendo usada
getChildAt(getCurrentItem())
para obter a visão filho atual para medir o que não está funcionando. Consulte a solução aqui: https://stackoverflow.com/a/16512217/1265583Abaixo, trabalha com a API 23:
fonte
requestLayout()
para que a altura seja ajustada à medida que avançamos de uma guia para a próxima. Você se lembra por quesuper
precisa ser chamado duas vezes? Notei que não funcionará de outra maneira.O código abaixo é a única coisa que funcionou para mim
1. Use esta classe para declarar um HeightWrappingViewPager:
2. Insira o pager da exibição de quebra de altura no seu arquivo xml:
3. Declare seu pager de exibição:
fonte
Eu edito a resposta cibernética para fazer com que o viewpager altere a altura, dependendo do item selecionado. A classe é a mesma do cybergen, mas adicionei um Vetor de números inteiros que são todas as alturas de visualizações filho do viewpager e podemos acessá-lo quando a página muda para atualizar a altura
Esta é a classe:
Em sua atividade, adicione um OnPageChangeListener
E aqui está o xml:
Por favor, corrija meu inglês, se necessário
fonte
heights
lista pode aumentar o infinito.measure
chamada seria várias vezes. Pode aumentar a lista de alturas. Outra situação é que o usuário pode chamarrequestLayout
(ousetLayoutParams
método, exatamente como o que você fez) para este viewPager manualmente, também medirá várias vezes.Se o que
ViewPager
você está usando é filho de umScrollView
AND e tem umPagerTitleStrip
filho, você precisará usar uma pequena modificação das ótimas respostas já fornecidas. Para referência, meu XML se parece com isso:No seu,
onMeasure
você precisa ADICIONAR a altura medida dePagerTitleStrip
se um for encontrado. Caso contrário, sua altura não será considerada na maior altura de todas as crianças, mesmo que ocupe espaço adicional.Espero que isso ajude outra pessoa. Desculpe que é um pouco de um hack ...
fonte
A maioria das soluções que vejo aqui parece estar fazendo uma medição dupla: primeiro medindo as visualizações da criança e depois chamando o
super.onMeasure()
Eu criei um costume
WrapContentViewPager
que é mais eficiente, funciona bem com o RecyclerView e o FragmentVocê pode conferir a demonstração aqui:
github / ssynhtn / WrapContentViewPager
e o código da classe aqui: WrapContentViewPager.java
fonte
Eu tenho um cenário semelhante (mas mais complexo). Eu tenho uma caixa de diálogo que contém um ViewPager.
Uma das páginas filhas é curta, com uma altura estática.
Outra página filha deve sempre ser a mais alta possível.
Outra página filha contém um ScrollView, e a página (e, portanto, a caixa de diálogo inteira) deve WRAP_CONTENT se o conteúdo do ScrollView não precisar da altura total disponível para a caixa de diálogo.
Nenhuma das respostas existentes funcionou completamente para esse cenário específico. Espere, é um passeio esburacado.
Muito obrigado a @Raanan pelo código para medir visualizações e medir a altura da decoração. Eu tive problemas com a biblioteca dele - a animação gaguejou e acho que meu ScrollView não rolaria quando a altura da caixa de diálogo fosse curta o suficiente para exigir isso.
fonte
no meu caso, a adição
clipToPadding
resolveu o problema.Felicidades!
fonte
No meu caso, a adição do android: fillViewport = "true" resolveu o problema
fonte
No meu caso, eu precisava de um viewpager com um wrap_content para o elemento e animação atualmente selecionados ao aplicar o tamanho. Abaixo você pode ver minha implementação. Alguém pode vir a calhar.
Adicione attrs.xml no projeto:
E use:
fonte
Esse ViewPager é redimensionado apenas para os filhos visíveis atuais (não o maior de seus filhos reais)
A ideia de https://stackoverflow.com/a/56325869/4718406
}
fonte
Meça a altura do ViewPager:
chamada setPrimaryView (Exibir) :
fonte
Forneça o layout pai do ViewPager como
NestedScrollView
Não se esqueça de definir
android:fillViewport="true"
Isso expandirá a visualização de rolagem e o conteúdo de seu filho para preencher a janela de visualização.
https://developer.android.com/reference/android/widget/ScrollView.html#attr_android:fillViewport
fonte
Você pode mudar para o ViewPager2. É uma versão atualizada do ViewPager. Ele faz o mesmo que o ViewPager, mas de maneira mais inteligente e eficiente. O ViewPager2 vem com uma variedade de novos recursos. Obviamente, o problema do Wrap Wrap foi resolvido pelo ViewPager2.
Da documentação do Android: "O ViewPager2 substitui o ViewPager, abordando a maioria dos pontos problemáticos de seu antecessor, incluindo suporte de layout da direita para a esquerda, orientação vertical, coleções de fragmentos modificáveis etc."
Eu recomendo este artigo para iniciantes:
https://medium.com/google-developer-experts/exploring-the-view-pager-2-86dbce06ff71
fonte