Manter a posição de deslocamento quando adicionar ao ListView com reverso infinito de rolagem
-
21-12-2019 - |
Pergunta
Eu estou construindo um bate-papo como aplicativo para Android, semelhante ao Hangouts.Para este efeito, eu estou usando uma vertical ListView com stackFromBottom=true
e transcriptMode="normal"
.
A lista é ordenada de mensagens mais antigas (superior) para o mais jovem mensagens (parte inferior).No estado normal, o ListView é deslocada para a parte inferior, mostrando o mais jovem mensagem.
O ListView usa o inverso de um fim-de rolagem adaptador para carregar mais (mais) mensagens quando o usuário rola para o topo da lista.Uma vez que as mensagens mais antigas são carregados, eles são adicionados ao topo da lista.
O comportamento desejado é que o ListView mantém o seu deslocamento de posição para a parte inferior da lista, quando as mensagens mais antigas são adicionados ao topo.Isto é, quando as mensagens mais antigas são adicionados ao topo, o deslocamento de exibição deve mostrar as mesmas mensagens que foram mostrados antes de adicionar as mensagens mais antigas.
Infelizmente, isso não funciona.Em vez de manter o deslocamento de posição para o fundo, o ListView mantém a tecla de deslocamento de posição para o topo da lista.Isto é, depois de adicionar as mensagens mais antigas da lista, a lista mostra que o primeiro (que eu.e mais antiga) de mensagens.
Existe uma maneira fácil para informar o ListView para manter o seu deslocamento de posição para a parte inferior, em vez de o superior, quando a adição de novos itens para o topo?
Atualização
Para fins de demonstração, de eu ter minimizado o caso de uso e o código tanto quanto possível.O exemplo a seguir cria uma cadeia de caracteres simples lista de matriz.Clicando em um item irá adicionar outro item no topo da lista.Longa-ao Clicar em um item adicionar outro item na parte inferior da lista.
Tudo funciona bem quando a adição de itens na parte inferior da lista (longa-clique).Ao adicionar os itens no topo da lista (clique simples), então existem 3 casos:
- Se a lista foi deslocada para a parte inferior, em seguida, tudo funciona bem.Depois de adicionar o item para o topo, a lista ainda é deslocada para a parte inferior.
- Se a lista não é deslocada para a parte inferior (nem o superior) e, em seguida, a lista vai manter a sua desloque-posição y (a partir do topo).Isso faz com que a lista parece "saltar" de um item para cima.Eu gostaria que a lista não para "jump up" neste caso, eu.e eu gostaria de manter a deslocar-posição y do fundo.
- Se a lista é deslocado para a parte superior, em seguida, o mesmo acontece no caso de 2.O preferido comportamento é o mesmo caso 2.
(Os 2 últimos casos são na verdade o mesmo.Separei deles, porque o problema pode ser melhor demonstrada no caso de 2.)
Código
public class MyListActivity extends Activity {
int topIndex = 1;
int bottomIndex = 20;
protected final void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_list_activity);
final ListView list = (ListView) findViewById(R.id.list);
list.setTranscriptMode(ListView.TRANSCRIPT_MODE_NORMAL);
list.setStackFromBottom(true);
final ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, android.R.id.text1);
for (int i = topIndex; i <= bottomIndex; i++) {
adapter.add(Integer.toString(i));
}
list.setAdapter(adapter);
list.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
adapter.insert(Integer.toString(--topIndex), 0);
}
});
list.setOnItemLongClickListener(new OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
adapter.add(Integer.toString(++bottomIndex));
return true;
}
});
}
}
Solução
Eu já descobriu isso.Onde é que você está recebendo novos dados que eu chamo o seguinte antes de alterar os dados de placa:
int firstVisibleItem = list.getFirstVisiblePosition();
int oldCount = adapter.getCount();
View view = list.getChildAt(0);
int pos = (view == null ? 0 : view.getBottom());
Em seguida, eu a chamo de:
adapter.setData(data);
list.setSelectionFromTop(firstVisibleItem + adapter.getCount() - oldCount + 1, pos);
Outras dicas
Em primeiro lugar obter a firstVisiblePosition (ou o Último, desde a sua cabeça para baixo.Yo chegou a tentar e verifique por si mesmo) e, em seguida, obter o topo da Vista de que é adicionada à Lista e, em seguida, usando setSe;ectionFromTop() método, você pode se deslocar para o local desejado.
Código:
int index = mList.getFirstVisiblePosition();
View v = mList.getChildAt(0); //or upside down (list.size - 1)
int top = (v == null) ? 0 : v.getTop(); //returns the top of the view its Y co-ordinates. [Doc][1]
mList.setSelectionFromTop(index, top);
Editar a conta para obter informações adicionais:
Eu acho que eu encontrei o seu problema.Eu replicado seu descritos casos de uso usando um autônomo lista como o modo de exibição somente em XML:
<ListView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
Eu corrigi o problema para seguir o seu desejado casos de uso através do aninhamento de layout em um layout pai:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ListView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
</FrameLayout>
depois de inserir o registro em seu adaptador você pode tentar usar
yourListView.setSelection(yourAdapter.getCount() - 1);