Manter a posição de deslocamento quando adicionar ao ListView com reverso infinito de rolagem

StackOverflow https://stackoverflow.com//questions/22051556

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;
      }
    });
  }
}
Foi útil?

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);

De origem.

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);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top