Estou usando o novo CoordinatorLayout com AppBarLayout e CollapsingToolbarLayout. Abaixo do AppBarLayout, tenho um RecyclerView com uma lista de conteúdo.
Eu verifiquei que a rolagem de arremesso funciona no RecyclerView quando estou rolando a lista para cima e para baixo. No entanto, eu também gostaria que o AppBarLayout rolasse suavemente durante a expansão.
Ao rolar para cima para expandir o CollaspingToolbarLayout, a rolagem para imediatamente após levantar o dedo da tela. Se você rolar para cima em um movimento rápido, às vezes o CollapsingToolbarLayout também recolhe. Esse comportamento com o RecyclerView parece funcionar de maneira muito diferente do que ao usar um NestedScrollView.
Tentei definir diferentes propriedades de rolagem na recyclerview, mas não consegui descobrir isso.
Aqui está um vídeo mostrando alguns dos problemas de rolagem. https://youtu.be/xMLKoJOsTAM
Aqui está um exemplo mostrando o problema com o RecyclerView (CheeseDetailActivity). https://github.com/tylerjroach/cheesesquare
Aqui está o exemplo original que usa um NestedScrollView de Chris Banes. https://github.com/chrisbanes/cheesesquare
Respostas:
A resposta de Kirill Boyarshinov estava quase correta.
O principal problema é que o RecyclerView às vezes está dando uma direção incorreta, então se você adicionar o seguinte código à resposta dele, ele funcionará corretamente:
Eu espero que isso ajude.
fonte
if (target instanceof SwipeRefreshLayout && velocityY < 0) { target = ((SwipeRefreshLayout) target).getChildAt(0); }
antesif (target instanceof RecyclerView && velocityY < 0) {
Parece que a
v23
atualização ainda não foi corrigida.Eu encontrei uma espécie de hack para corrigi-lo com arremessar para baixo. O truque é reconsiderar o evento fling se o filho superior do ScrollingView estiver próximo do início dos dados no Adapter.
Use-o no seu layout assim:
EDIT: o reconsumo de evento de lançamento agora é baseado em
verticalScrollOffset
vez da quantidade de itens da parte superiorRecyclerView
.EDIT2: Verifique o destino como
ScrollingView
instância da interface em vez deRecyclerView
. AmbosRecyclerView
eNestedScrollingView
implementá-lo.fonte
verticalScrollOffset
que é mais geral. Agora, o evento fling será reconsumido quandorecyclerView
rolado para cima.target instanceof RecyclerView
paratarget instanceof NestedScrollView
, ou mais, para o caso genérico paratarget instanceof ScrollingView
. Eu atualizei a resposta.Encontrei a correção aplicando OnScrollingListener ao recyclerView. agora funciona muito bem. O problema é que a reciclagem forneceu o valor consumido errado e o comportamento não sabe quando a reciclagem é rolada para o topo.
fonte
CoordinatorLayout
eViewPager
muito obrigado pela solução mais esperada. Escreva um GIST para o mesmo, para que outros desenvolvedores também possam se beneficiar. Também estou compartilhando esta solução. Obrigado novamente.Foi corrigido desde o design de suporte 26.0.0.
fonte
Esta é uma versão simples do Google Support Design AppBarLayout. Se você estiver usando o AppBarLayout, saberá que há um problema com o fling.
Consulte a Biblioteca aqui. Https://github.com/henrytao-me/smooth-app-bar-layout
fonte
É um bug de visualização de reciclagem. Ele deveria ser corrigido na v23.1.0.
consulte https://code.google.com/p/android/issues/detail?id=177729
fonte
v26.0.1
!Este é o meu Layout e o pergaminho. Está funcionando como deveria.
fonte
Minha solução até agora, com base em Mak Sing e Manolo Garcia respostas de .
Não é totalmente perfeito. Por enquanto, não sei como recalcular uma velocidade de valide para evitar um efeito estranho: a barra de aplicativos pode se expandir mais rapidamente que a velocidade de rolagem. Mas o estado com uma barra de aplicativos expandida e uma exibição de reciclador rolada não pode ser alcançado.
fonte
Field viewFlingerField = recyclerView.getClass().getDeclaredField("mViewFlinger"); viewFlingerField.setAccessible(true); Object flinger = viewFlingerField.get(recyclerView); Field scrollerField = flinger.getClass().getDeclaredField("mScroller"); scrollerField.setAccessible(true); ScrollerCompat scroller = (ScrollerCompat) scrollerField.get(flinger); velocity = Math.signum(mVelocity) * Math.abs(scroller.getCurrVelocity());
No meu caso, eu estava entendendo o problema de arremessar o
RecyclerView
não rolaria suavemente, fazendo com que ficasse preso.Isso porque, por algum motivo, eu tinha esquecido que eu tinha colocado o meu
RecyclerView
em umNestedScrollView
.É um erro bobo, mas levei um tempo para descobrir ...
fonte
Eu adiciono uma visão da altura de 1dp dentro do AppBarLayout e funciona muito melhor. Esse é o meu layout.
fonte
Já existem algumas soluções bastante populares aqui, mas depois de brincar com elas, encontrei uma solução mais simples que funcionou bem para mim. Minha solução também garante que ela
AppBarLayout
seja expandida apenas quando o conteúdo rolável chegar ao topo, uma vantagem sobre outras soluções aqui.fonte
A resposta aceita não funcionou para mim porque eu tinha
RecyclerView
dentro de aSwipeRefreshLayout
e aViewPager
. Esta é a versão aprimorada que procura umRecyclerView
na hierarquia e deve funcionar para qualquer layout:fonte
Resposta: Foi corrigido na biblioteca de suporte v26
mas a v26 tem algum problema no arremesso. Às vezes, o AppBar recupera mesmo que o arremesso não seja muito difícil.
Como removo o efeito de salto na appbar?
Se você encontrar o mesmo problema ao atualizar para o suporte v26, aqui está o resumo desta resposta .
fonte
Julian Os está certo.
A resposta de Manolo Garcia não funciona se a vista da reciclagem estiver abaixo do limite e rolar. Você deve comparar
offset
a visão de reciclagem e avelocity to the distance
posição do item, não.Eu fiz a versão java referindo-me ao código kotlin de julian e subtraia a reflexão.
fonte
BaseApplication
Encontrei a correção por Eniz Bilgin https://stackoverflow.com/a/45090239/7639018
O problema foi resolvido com as bibliotecas deste repositório.
( https://developer.android.com/topic/libraries/support-library/setup.html )
fonte
Com referência ao rastreador de problemas do Google , foi corrigido com a versão Android 26.0.0-beta2 da biblioteca de suporte
Atualize a sua biblioteca de suporte Android versão 26.0.0-beta2.
Se algum problema persistir, informe no rastreador de problemas do Google que eles serão reabertos para examinar.
fonte
Adicionando outra resposta aqui, como as anteriores, não preencheu minhas necessidades completamente ou não funcionou muito bem. Este é parcialmente baseado em idéias espalhadas aqui.
Então, o que esse faz?
Movimento descendente do cenário: se o AppBarLayout estiver recolhido, ele permitirá que o RecyclerView seja executado sozinho sem fazer nada. Caso contrário, ele recolhe o AppBarLayout e impede que o RecyclerView faça seu arremesso. Assim que ele é recolhido (até o ponto que a velocidade especificada exige) e se houver velocidade restante, o RecyclerView é arremessado com a velocidade original menos o que o AppBarLayout acabou de consumir.
Movimento ascendente do cenário: se o deslocamento de rolagem do RecyclerView não for zero, ele será arremessado com a velocidade original. Assim que isso terminar e se ainda houver velocidade restante (ou seja, o RecyclerView rolou para a posição 0), o AppBarLayout é expandido até o ponto em que a velocidade original menos as demandas consumidas. Caso contrário, o AppBarLayout será expandido até o ponto que a velocidade original exige.
AFAIK, esse é o comportamento incorreto.
Há muita reflexão envolvida, e é bastante personalizado. Ainda não foram encontrados problemas. Também está escrito em Kotlin, mas entendê-lo não deve ser problema. Você pode usar o plug-in IntelliJ Kotlin para compilá-lo no bytecode -> e descompilá-lo novamente em Java. Para usá-lo, coloque-o no pacote android.support.v7.widget e defina-o como o comportamento do CoordinatorLayout.LayoutParams do AppBarLayout no código (ou adicione o construtor aplicável xml ou algo assim)
fonte
esta é a minha solução no meu projeto.
basta parar o mScroller ao obter Action_Down
xml:
FixAppBarLayoutBehavior.java:
fonte
para androidx,
Se o seu arquivo de manifesto tiver uma linha android: hardwareAccelerated = "false", exclua-o.
fonte