문제

나는 행 아웃과 비슷한 채팅과 같은 안드로이드 응용 프로그램을 구축하고 있습니다. 이 목적을 위해 stackFromBottom=truetranscriptMode="normal"가있는 수직 ListView를 사용하고 있습니다.

목록은 이전 메시지 (상단)에서 젊은 메시지 (하단)로 정렬됩니다. 정상 상태에서 ListView는 가장 젊은 메시지를 보여주는 하단으로 스크롤됩니다.

ListView는 사용자가 목록의 맨 위로 스크롤되면리스트 뷰가 역 끝없는 스크롤 어댑터를 사용하여 더 많은 (이전) 메시지를로드합니다. 이전 메시지가로드되면 목록의 맨 위에 추가됩니다.

원하는 동작은 이전 메시지가 맨 위에 추가 될 때 ListView가 목록의 아래쪽에 스크롤 위치를 유지하는 것입니다. 즉, 이전 메시지가 상단에 추가되면 스크롤 뷰는 이전 메시지를 추가하기 전에 표시된 것과 동일한 메시지를 표시해야합니다.

불행히도, 이것은 작동하지 않습니다. 아래쪽으로 스크롤 위치를 유지하는 대신 listView는 스크롤 위치를 목록 의 맨 위로 유지합니다. 즉, 목록에 이전 메시지를 추가 한 후에 목록은 최상위 (i.e 가장 오래된) 메시지가 표시됩니다.

ListView가 상단에 새 항목을 추가 할 때 상단 대신 스크롤 위치를 하단으로 유지하도록 쉽게 표시하는 것이 쉬운 방법이 있습니까?

업데이트

시연 목적을 위해, 나는 가능한 한 유스 케이스 및 코드를 최소화했다. 다음 예제에서는 간단한 문자열 배열 목록을 만듭니다. 항목을 클릭하면 목록 맨 위에 다른 항목이 추가됩니다. 항목을 길게 클릭하면 목록의 맨 아래에 다른 항목이 추가됩니다.

목록의 맨 아래에 항목을 추가 할 때 모든 것이 잘 작동합니다 (긴 클릭). 목록 상단에 항목을 추가 할 때 (간단한 클릭) 3 가지 경우가 있습니다.

  • 목록이 바닥으로 스크롤되는 경우 모든 것이 잘 작동합니다. 상단에 항목을 추가 한 후 목록이 여전히 아래쪽으로 스크롤됩니다.
  • 목록이 하단으로 스크롤되지 않으면 (상단에도) 목록은 Scroll-Y 위치를 유지합니다 (상단에서). 이렇게하면 목록이 하나의 항목을 "점프"하는 것처럼 보입니다. 이 경우 목록을 "으스립니다"하지 않으려면 I.E 맨 아래에서 스크롤 Y 위치를 유지하고 싶습니다.
  • 목록이 맨 위로 스크롤되는 경우 2 대의 경우와 동일하게 발생합니다. 기본 동작은 케이스 2와 동일합니다.

(마지막 2 가지 경우는 사실 동일합니다. 문제가 사례 2에서 문제를 더 잘 보여줄 수 있기 때문에이를 분리했습니다.)

코드

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

도움이 되었습니까?

해결책

나는 이것을 알아 냈습니다.어댑터의 데이터를 변경하기 전에 새 데이터를 가져 오는 새 데이터를 얻는 것이 무엇이면 다음을 수행합니다.

int firstVisibleItem = list.getFirstVisiblePosition();
int oldCount = adapter.getCount();
View view = list.getChildAt(0);
int pos = (view == null ? 0 :  view.getBottom());
.

다음 호출 :

adapter.setData(data);

list.setSelectionFromTop(firstVisibleItem + adapter.getCount() - oldCount + 1, pos);
.

다른 팁

처음 처음으로 거꾸로 이후 마지막 사람을 얻으려면, 자신을 직접 확인하고 목록에 추가 한 다음 setse; ectectFromtop () 메서드를 사용하여 뷰의 상단을 얻습니다.원하는 위치로 스크롤 할 수 있습니다.

코드 :

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

소스.

추가 정보를 확인하려면 편집 :

나는 당신의 문제를 발견했다고 생각합니다.XML의 유일한보기로 독립 실행 형 목록을 사용하여 설명한 사용 사례를 복제했습니다.

<ListView
    android:id="@+id/list"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
</ListView>
.

상위 레이아웃에 레이아웃을 중첩하여 원하는 사용 사례를 따르려면 문제가 해결되었습니다.

<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>
.

어댑터에 레코드를 삽입 한 후에는

를 사용하려고 할 수 있습니다.
   yourListView.setSelection(yourAdapter.getCount() - 1);
.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top