안드로이드 끝없는 목록


232

더 많은 항목을로드 할 수 있도록 목록 끝에 도달했을 때 목록을 작성하려면 어떻게해야합니까?


9
나는 CommonWare의 EndlessAdapter 추천 : github.com/commonsguy/cwac-endless . 이 질문에서 다른 질문에 대한 답을 찾았습니다 : stackoverflow.com/questions/4667064/… .
Tyler Collier

똑같은 일이 필요합니다. 어떤 사람이 도와 줄 수 있습니까? .. stackoverflow.com/questions/28122304/…

답변:


269

한 가지 해결책은 구현 시 편리한 방법으로 OnScrollListener항목 추가 등 을 구현하고 변경 ListAdapter하는 onScroll것입니다.

다음 ListActivity은 40부터 시작하여 사용자가 목록의 끝으로 스크롤 할 때 항목을 추가하는 정수 목록을 보여줍니다.

public class Test extends ListActivity implements OnScrollListener {

    Aleph0 adapter = new Aleph0();

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setListAdapter(adapter); 
        getListView().setOnScrollListener(this);
    }

    public void onScroll(AbsListView view,
        int firstVisible, int visibleCount, int totalCount) {

        boolean loadMore = /* maybe add a padding */
            firstVisible + visibleCount >= totalCount;

        if(loadMore) {
            adapter.count += visibleCount; // or any other amount
            adapter.notifyDataSetChanged();
        }
    }

    public void onScrollStateChanged(AbsListView v, int s) { }    

    class Aleph0 extends BaseAdapter {
        int count = 40; /* starting amount */

        public int getCount() { return count; }
        public Object getItem(int pos) { return pos; }
        public long getItemId(int pos) { return pos; }

        public View getView(int pos, View v, ViewGroup p) {
                TextView view = new TextView(Test.this);
                view.setText("entry " + pos);
                return view;
        }
    }
}

웹 데이터로드와 같은 장기 실행 작업에는 별도의 스레드를 사용해야하며 마지막 목록 항목의 진행률 (예 : 마켓 또는 gmail 앱)을 표시 할 수 있습니다.


3
화면 중간에서 스크롤을 중지하면 어댑터 크기가 증가하지 않습니까? 실제로 목록 맨 아래에 도달 할 때 다음 10 개만로드해야합니다.
Matthias

9
BaseAdapter를 사용하여 이와 같은 많은 예를 발견했습니다. 데이터베이스를 사용하는 경우 SimpleCursorAdapter를 사용해보십시오. 목록에 추가해야 할 경우 데이터베이스를 업데이트하고 새 커서를 가져온 다음 notifyDataSetChanged와 함께 SimpleCursorAdapter # changeCursor를 사용하십시오. 서브 클래 싱이 필요하지 않으며 BaseAdapter (데이터베이스를 사용하는 경우에만)보다 성능이 우수합니다.
brack

1
notifyDataSetChanged ()를 호출 한 후 목록 맨 위로 이동합니다. 어떻게 방지 할 수 있습니까?
그릴

2
참고-이 접근법을 사용했지만 visibleCount가 0 일 때 확인을 추가해야했습니다. 각 목록에 대해 firstVisible, visibleCount 및 totalCount가 모두 0이며 기술적으로 조건을 충족하지만 onScroll에 대한 콜백이 하나 있습니다. 더로드하고 싶을 때
Eric Mill

5
이 코드의 또 다른 문제점 firstVisible + visibleCount >= totalCount은 리스너를 여러 번 호출 하여 조건 이 여러 번 충족 된다는 것 입니다. 추가 기능이 웹 요청 인 경우 (아마도 가능할 것임) 요청이 진행 중인지 다른 확인을 추가하십시오. 반면에 totalCount가 Previous total count와 같지 않은지 확인하십시오. 목록에서 같은 수의 항목에 대해 여러 요청이 필요하지 않기 때문입니다.
Subin Sebastian

94

내 앱에 사용한 솔루션을 제공하고 싶었습니다.

또한 OnScrollListener인터페이스를 기반으로 하지만 스크롤 작업 중에 가시 / 총 카운트 계산이 수행되지 않으므로 로우 엔드 장치에서 스크롤 성능이 훨씬 뛰어납니다.

  1. 당신의 ListFragment또는 ListActivity구현 하자OnScrollListener
  2. 해당 클래스에 다음 메소드를 추가하십시오.

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {
        //leave this empty
    }
    
    @Override
    public void onScrollStateChanged(AbsListView listView, int scrollState) {
        if (scrollState == SCROLL_STATE_IDLE) {
            if (listView.getLastVisiblePosition() >= listView.getCount() - 1 - threshold) {
                currentPage++;
                //load more list items:
                loadElements(currentPage);
            }
        }
    }

    where currentPage는 목록에 추가해야하는 데이터 소스의 페이지이며 threshold, 표시되는 경우로드 프로세스를 트리거해야하는 목록 항목 (끝부터 계산)의 수입니다. 예를 들어로 설정 threshold하면 0더 많은 항목을로드하기 위해 사용자가 목록의 맨 끝으로 스크롤해야합니다.

  3. (선택 사항) 보시다시피 "로드 추가 검사"는 사용자가 스크롤을 멈출 때만 호출됩니다. 사용성을 향상시키기 위해을 통해로드 표시기를 팽창시키고 목록 끝에 추가 할 수 있습니다 listView.addFooterView(yourFooterView). 바닥 글보기의 한 가지 예 :

    <?xml version="1.0" encoding="utf-8"?>
    
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/footer_layout"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:padding="10dp" >
    
        <ProgressBar
            android:id="@+id/progressBar1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_gravity="center_vertical" />
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_toRightOf="@+id/progressBar1"
            android:padding="5dp"
            android:text="@string/loading_text" />
    
    </RelativeLayout>
  4. (선택 사항) 마지막으로 listView.removeFooterView(yourFooterView)더 이상 항목이나 페이지가없는 경우 호출하여로드 표시기를 제거하십시오 .


나는 이것을 시도했지만 ListFragment에서는 작동하지 않습니다. ListFragment에서 어떻게 사용할 수 있습니까?
zeeshan

글쎄, 나는 ListFragment문제없이 함께 사용합니다 -위의 각 단계를 따르십시오. 그러면 괜찮을 것입니다.) 또는 오류 메시지를 제공 할 수 있습니까?
saschoar

당신이 놓친 것은이 SO의 대답에 설명되어 있습니다 : stackoverflow.com/a/6357957/1478093 -getListView().setOnScrollListener(this)
TBieniek

7
참고 : 목록보기에서 바닥 글 추가 및 제거에 문제가 있습니다 (바닥 글을 추가하기 전에 setAdapter를 호출하면 바닥 글이 표시되지 않음). 바닥 글을 제거하지 않고 직접 바닥 글보기의 가시성을 수정했습니다.
dvd

loadElements (currentPage)에 무엇을 추가해야합니까? 내 AsyncTask 또는 스레드를 호출합니까?
android_developer

20

onScrollListener의 도움으로 목록의 끝을 감지 할 수 있습니다 . 작업 코드는 다음과 같습니다.

@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    if (view.getAdapter() != null && ((firstVisibleItem + visibleItemCount) >= totalItemCount) && totalItemCount != mPrevTotalItemCount) {
        Log.v(TAG, "onListEnd, extending list");
        mPrevTotalItemCount = totalItemCount;
        mAdapter.addMoreData();
    }
}

이를 수행하는 다른 방법 (어댑터 내부)은 다음과 같습니다.

    public View getView(int pos, View v, ViewGroup p) {
            if(pos==getCount()-1){
                addMoreData(); //should be asynctask or thread
            }
            return view;
    }

이 메소드는 여러 번 호출되므로 여러 호출을 차단하려면 다른 조건을 추가해야합니다 addMoreData().

목록에 모든 요소를 ​​추가 할 때 어댑터 내부의 notifyDataSetChanged () 를 호출 하여보기를 업데이트하십시오 (UI 스레드에서 실행되어야 함 -runOnUiThread )


7
의보기를 반환하는 것 외에 다른 작업을 수행하는 것은 좋지 않습니다 getView. 예를 들어, 사용자 pos가 볼 수 있다고 보장되지는 않습니다 . 단순히 ListView 측정 항목 일 수 있습니다.
Thomas Ahle

10 개 항목을 스크롤 한 후 더 많은 항목을로드하고 싶습니다. 그러나 9 번째 항목에서 10 번째 항목이 표시되기 전에로드가 시작된다는 것을 알았습니다.
Atul Bhardwaj

4

에서 Ognyan Bankov GitHub나는 간단하고 작동 해결책을 발견!

그것은 Volley HTTP library안드로이드 앱을위한 네트워킹을 더 쉽고 가장 중요하게, 더 빠르게 만드는 것을 사용합니다. 발리는 오픈 AOSP 리포지토리를 통해 사용할 수 있습니다.

주어진 코드는 다음을 보여줍니다.

  1. HTTP 페이지 매김 요청으로 채워지는 ListView입니다.
  2. NetworkImageView의 사용법.
  3. 미리 읽기 기능이있는 "Endless"ListView 페이지 매김.

미래의 일관성을 위해 나는 Bankov의 repo를 포크했다 .


2

다음은로드하는 동안 ListView의 끝에로드보기를 쉽게 표시 할 수있는 솔루션입니다.

여기에서 수업을 볼 수 있습니다.

https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/helper/ListViewWithLoadingIndicatorHelper.java- 사용할 수 있도록 돕는 도우미 SimpleListViewWithLoadingIndicator에서 확장하지 않고 기능.

https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/listener/EndlessScrollListener.java- 사용자가 데이터로드를 시작할 때 리스너 ListView의 맨 아래에 도달하려고합니다.

https://github.com/CyberEagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/view/SimpleListViewWithLoadingIndicator.java-EndlessListView . 이 클래스를 직접 사용하거나 확장 할 수 있습니다.


1

조금 늦을 수도 있지만 다음과 같은 해결책이 제 경우에는 매우 유용했습니다. 당신이해야 할 방법은 ListView에 추가하고 Footer그것을 만드는 것 addOnLayoutChangeListener입니다.

http://developer.android.com/reference/android/widget/ListView.html#addFooterView(android.view.View)

예를 들면 다음과 같습니다.

ListView listView1 = (ListView) v.findViewById(R.id.dialogsList); // Your listView
View loadMoreView = getActivity().getLayoutInflater().inflate(R.layout.list_load_more, null); // Getting your layout of FooterView, which will always be at the bottom of your listview. E.g. you may place on it the ProgressBar or leave it empty-layout.
listView1.addFooterView(loadMoreView); // Adding your View to your listview 

...

loadMoreView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
    @Override
    public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
         Log.d("Hey!", "Your list has reached bottom");
    }
});

바닥 글이 표시되고 매력처럼 작동하면이 이벤트가 한 번 발생합니다.


0

이 문제의 핵심은 더 많은 이벤트를 감지하고 데이터에 대한 비동기 요청을 시작한 다음 목록을 업데이트하는 것입니다. 또한 로딩 표시기와 다른 데코레이터가있는 어댑터가 필요합니다. 실제로 일부 경우에는 문제가 매우 복잡합니다. 그냥 OnScrollListener가끔 항목이 화면을 채울하지 않기 때문에 구현은 충분하지 않습니다.

에 대한 끝없는 목록을 지원하는 개인 패키지를 작성했으며 여러 페이지 소스에서 데이터를 매우 쉽게 가져올 RecyclerView수있는 비동기 로더 구현 AutoPagerFragment을 제공합니다 . RecyclerView다음 페이지뿐만 아니라 사용자 정의 이벤트에 원하는 페이지를로드 할 수 있습니다 .

주소는 다음과 같습니다. https://github.com/SphiaTower/AutoPagerRecyclerManager


링크가 끊어졌습니다.
DSlomer64


0

나는 그것과 매우 비슷한 다른 솔루션에서 일하고 있지만,를 사용 footerView하여 사용자가을 클릭하여 더 많은 요소를 다운로드 할 수있는 가능성을 제공하고 있습니다 footerView. 나는 "메뉴"를 사용하고 있습니다 ListView. 상위보기에서이 "메뉴"는의 하단을 숨기 ListView므로 listView메뉴를 스크롤 할 때 메뉴가 사라지고 스크롤 상태가 유휴 상태 일 때 메뉴가 다시 나타나지만 사용자가의 끝으로 스크롤하면 listView"요청" 이 경우 footerView메뉴가 표시되면 메뉴가 표시되지 않고 footerView더 많은 콘텐츠를로드 할 수 있습니다. 여기 코드가 있습니다 :

문안 인사.

listView.setOnScrollListener(new OnScrollListener() {

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        // TODO Auto-generated method stub
        if(scrollState == SCROLL_STATE_IDLE) {
            if(footerView.isShown()) {
                bottomView.setVisibility(LinearLayout.INVISIBLE);
            } else {
                bottomView.setVisibility(LinearLayout.VISIBLE);
            } else {
                bottomView.setVisibility(LinearLayout.INVISIBLE);
            }
        }
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {

    }
});

0

나는 오래된 질문을 알고 있으며 안드로이드 세계는 주로 RecyclerViews로 옮겨 갔지만 관심있는 사람이라면 라이브러리가 매우 흥미로울 것입니다.

ListView와 함께 사용되는 BaseAdapter를 사용하여 목록이 마지막 항목으로 스크롤 된시기 또는 마지막 항목에서 멀리 스크롤되는시기를 감지합니다.

작동 방식을 빠르게 이해하는 데 사용할 수있는 예제 프로젝트 (거의 100 줄의 활동 코드)가 제공됩니다.

간단한 사용법 :

class Boy{

private String name;
private double height;
private int age;
//Other code

}

Boy 오브젝트를 보유하는 어댑터는 다음과 같습니다.


public class BoysAdapter extends EndlessAdapter<Boy>{




        ViewHolder holder = null;


        if (convertView == null) {
            LayoutInflater inflater = LayoutInflater.from(parent
                    .getContext());

            holder = new ViewHolder();

            convertView = inflater.inflate(
                    R.layout.list_cell, parent, false);


            holder.nameView = convertView.findViewById(R.id.cell);

            // minimize the default image.
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        Boy boy = getItem(position);

        try {
            holder.nameView.setText(boy.getName());

            ///Other data rendering codes.

        } catch (Exception e) {
            e.printStackTrace();
        }

        return super.getView(position,convertView,parent);

}

BoysAdapter의 getView 메소드가 EndlessAdapter 수퍼 클래스의 getView메소드에 대한 호출을 리턴하는 방법에 주목하십시오 . 100 % 필수입니다.

이제 어댑터를 작성하려면 다음을 수행하십시오.

   adapter = new ModelAdapter() {
            @Override
            public void onScrollToBottom(int bottomIndex, boolean moreItemsCouldBeAvailable) {

                if (moreItemsCouldBeAvailable) { 
                    makeYourServerCallForMoreItems();
                } else {
                    if (loadMore.getVisibility() != View.VISIBLE) {
                        loadMore.setVisibility(View.VISIBLE);
                    }
                }
            }

            @Override
            public void onScrollAwayFromBottom(int currentIndex) { 
                loadMore.setVisibility(View.GONE);
            }

            @Override
            public void onFinishedLoading(boolean moreItemsReceived) { 
                if (!moreItemsReceived) {
                    loadMore.setVisibility(View.VISIBLE);
                }
            }
        };

loadMore항목은 버튼이나 URL에서 더 많은 데이터를 가져 오기 위해 클릭 할 수있는 다른 UI 요소입니다. 코드에 설명 된대로 배치하면 어댑터는 해당 단추를 표시 할시기와 비활성화 할시기를 정확하게 알고 있습니다. xml에서 버튼을 만들고 위의 어댑터 코드에 표시된 것처럼 배치하십시오.

즐겨.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.