Vista de lista Role até o final da lista após atualizar a lista

292

Gostaria de garantir que a lista seja rolada até o final, depois de atualizar a exibição da lista usando o listAdapter, para exibir o último elemento inserido na lista. Como posso fazer isso ?

Eu tentei isso, mas sem sorte:

lv.setTranscriptMode(ListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);

obrigado

jramirez
fonte
tente fazer isso funcionar ... messagesListView.setTranscriptMode (ListView.TRANSCRIPT_MODE_NORMAL); messagesListView.setStackFromBottom (true);
precisa
O lv.setTranscriptMode (ListView.TRANSCRIPT_MODE_ALWAYS_SCROLL) garante apenas que o listView seja rolado para baixo depois de chamar adapter.notifyDataSetChanged. Se isso não estiver funcionando, tente definir essa propriedade no xml, como você pode ver nas postagens abaixo.
tomm

Respostas:

418

Supondo que você saiba quando os dados da lista foram alterados, você pode manualmente dizer à lista para rolar até o final, definindo a seleção da lista para a última linha. Algo como:

private void scrollMyListViewToBottom() {
    myListView.post(new Runnable() {
        @Override
        public void run() {
            // Select the last row so it will scroll into view...
            myListView.setSelection(myListAdapter.getCount() - 1);
        }
    });
}
Mason Lee
fonte
@Bhupendra que não é necessário. Você também pode ficar sem linha, como mostra a resposta de Warting.
Sagarpatidar
2
@Bhupendra setSelection () atualiza a interface do usuário. Ao chamar post (Runnable) na exibição, você garante que o código Runnable seja executado no encadeamento da UI do Android. Geralmente faça isso dessa maneira, a menos que você saiba que já está no segmento da interface do usuário ou esteja garantindo isso por outros meios.
Mason Lee
5
também parece que o uso de post sobre um recém-definido adaptador causas de rolagem animação, garantindo para a thread principal e usando setSelection imediatamente depois de definir o adaptador faz com que nenhuma animação de rolagem
Gianluca P.
1
O @SaifHamed, como comentado por Mason Lee na resposta de Kevin, também faz com que listas curtas tenham espaço "vazio" na parte superior da visualização em vez da parte inferior, o que provavelmente não é o comportamento pretendido.
dashhund
16
você também pode usar myListView.smoothScrollToPosition (myListAdapter.getCount () - 1); para rolagem suave
Zar E Ahmer 13/15
238

Você precisa usar estes parâmetros em sua exibição de lista:

  • Rolagem lv.setTranscriptMode(ListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);

  • Coloque o cabeçalho da lista no final lv.setStackFromBottom(true);

Você também pode definir esses parâmetros em XML, por exemplo. como isso:

<ListView
   ...
   android:transcriptMode="alwaysScroll"
   android:stackFromBottom="true" />
dev.serghini
fonte
27
Observe que, com essa abordagem, as linhas "empilham da parte inferior" da exibição à medida que são adicionadas. Isso significa que listas curtas terão espaço "vazio" na parte superior da visualização, em vez da parte inferior, o que nem sempre é o que se deseja.
Mason Lee
2
Pergunta rápida: De que maneira posso fazer a rolagem ser animada? Causa no momento em que notifico DataSetChanged (), ele pula sem animação?!?
Georg
@Georg Você desativou as animações nas Opções do desenvolvedor no seu dispositivo, talvez?
JonasCz - Restabelece Monica
35

Uma combinação de TRANSCRIPT_MODE_ALWAYS_SCROLL e setSelection fez com que funcionasse para mim

ChatAdapter adapter = new ChatAdapter(this);

ListView lv = (ListView) findViewById(R.id.chatList);
lv.setTranscriptMode(AbsListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
lv.setAdapter(adapter);

adapter.registerDataSetObserver(new DataSetObserver() {
    @Override
    public void onChanged() {
        super.onChanged();
        lv.setSelection(adapter.getCount() - 1);    
    }
});
Wärting
fonte
29

Consegui usar isso em resposta a um clique no botão, então acho que você também pode usá-lo depois de atualizar seu conteúdo:

myListView.smoothScrollToPosition(theListAdapter.getCount() -1);
Álex
fonte
1
Esta é uma otima soluçao. Simples, uma linha.
Josh Larson
12

Para obter isso em um ListFragment:

getListView().setTranscriptMode(ListView.TRANSCRIPT_MODE_ALWAYS_SCROLL); 
getListView().setStackFromBottom(true);`

Adicionada esta resposta, porque se alguém fizer uma pesquisa no google pelo mesmo problema com o ListFragment, ele simplesmente encontrará isso.

Saudações

Klatschen
fonte
9

Usando: Coloque o cabeçalho da lista na parte inferior lv.setStackFromBottom(true);

Trabalhou para mim e a lista é rolada para baixo automaticamente quando é trazida à visibilidade pela primeira vez. A lista então rola como deveria TRANSCRIPT_MODE_ALWAYS_SCROLL.

Kevin Parker
fonte
6
Observe que, com essa abordagem, as linhas "empilham da parte inferior" da exibição à medida que são adicionadas. Isso significa que listas curtas terão espaço "vazio" na parte superior da visualização em vez da parte inferior.
Mason Lee
5

eu uso

setTranscriptMode(ListView.TRANSCRIPT_MODE_NORMAL);

para adicionar entradas na parte inferior, e as entradas mais antigas rolam para cima, como uma transcrição de bate-papo

Plugie
fonte
Ligue getListView().smoothScrollToPosition(getListAdapter.getCount() - 1);no início para rolar para a parte inferior no início da atividade.
palindrom 29/01
4

A solução mais simples é:

    listView.setTranscriptMode(ListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
    listView.setStackFromBottom(true);
ucMedia
fonte
3

O modo de transcrição é o que você deseja e é usado pelo Google Talk e pelo aplicativo SMS / MMS. Você está chamando corretamente notifyDatasetChanged () no seu adaptador quando adiciona itens?

Romain Guy
fonte
Sim, eu sou. a lista é atualizada corretamente, mas sempre começa do topo. Eu só preciso adicionar o novo item e sempre rolar para o final da lista.
Jramirez 31/08
O modo de transcrição está realmente desabilitado pelo aplicativo SMS. Não me lembro exatamente o porquê.
Timmmm