Androidエンドレスリスト


232

リストの最後に到達したときに通知されるようにリストを作成して、さらにアイテムをロードするにはどうすればよいですか?


9
CommonWareのEndlessAdapter:github.com/commonsguy/cwac-endlessをお勧めします。私は別の質問へのこの回答からそれを見つけました:stackoverflow.com/questions/4667064/…
タイラーコリアー

私は、いずれかの助けthing..can同じ必要..?stackoverflow.com/questions/28122304/...

回答:


269

1つの解決策は、メソッドの便利な状態でを実装OnScrollListenerして変更(アイテムの追加など)を行うことです。ListAdapteronScroll

以下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;
        }
    }
}

実行時間の長いアクション(Webデータの読み込みなど)には個別のスレッドを使用する必要があり、最後のリストアイテム(marketまたはgmailアプリのように)の進行状況を示したい場合があります。


3
画面の中央でスクロールを停止すると、アダプターのサイズが増加しますか?実際にリストの一番下に達したときにのみ、次の10をロードする必要があります。
Matthias

9
BaseAdapterを使用したこのような例がたくさんあることに気づきました。データベースを使用している場合は、SimpleCursorAdapterを使用してみてください。リストに追加する必要がある場合は、データベースを更新し、新しいカーソルを取得して、notifyDataSetChangedとともにSimpleCursorAdapter#changeCursorを使用します。サブクラス化は必要なく、BaseAdapterよりもパフォーマンスが優れています(これも、データベースを使用している場合のみ)。
Brackの

1
notifyDataSetChanged()を呼び出した後、リストの一番上に表示されますが、どうすれば防ぐことができますか?
2011

2
注-私はこのアプローチを使用しましたが、visibleCountが0の場合のチェックを追加する必要がありました。リストごとに、onVisible、visibleCount、totalCountがすべて0である1つのコールバックを取得します。これは、技術的には条件を満たしていますが、もっとロードしたいとき。
Eric Mill

5
このコードのもう1つの問題はfirstVisible + visibleCount >= totalCount、リスナーへの複数の呼び出しで条件が複数回満たされることです。load-more関数がWebリクエストである場合(ほとんどの場合はそうです)、リクエストが実行されているかどうかのチェックを追加します。一方、リスト内の同じ数のアイテムに対して複数のリクエストを行う必要がないため、totalCountが前の合計カウントと等しくないかどうかを確認します。
Subin Sebastian 2012

94

私が自分のアプリに使用したソリューションを提供したかっただけです。

これもOnScrollListenerインターフェースに基づいていますが、スクロール操作中に表示/合計数の計算が実行されないため、ローエンドデバイスでのスクロールパフォーマンスがはるかに優れていることがわかりました。

  1. あなたのListFragmentListActivity実装してみましょう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);
            }
        }
    }
    

    ここで、currentPageはリストに追加する必要があるデータソースのページであり、表示されているthreshold場合にロードプロセスをトリガーする(最後から数えた)リストアイテムの数です。たとえばに設定threshold0た場合、より多くのアイテムをロードするために、ユーザーはリストの最後までスクロールする必要があります。

  3. (オプション)ご覧のとおり、「load-more check」は、ユーザーがスクロールを停止したときにのみ呼び出されます。使いやすさを向上させるには、を使用して、リストの最後にローディングインジケーターを膨らませて追加しlistView.addFooterView(yourFooterView)ます。このようなフッタービューの1つの例:

    <?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 2013

まあ、私はListFragment問題なくそれを使っています-上記の各手順に従ってください、あなたは大丈夫です;)それともエラーメッセージを提供できますか?
saschoar 2013

あなたが見逃している可能性がありますが、このSOの答えで説明されています。stackoverflow.com/a/6357957/1478093 -getListView().setOnScrollListener(this)
TBieniek

7
注:リストビューでのフッターの追加と削除は問題があります(フッターを追加する前にsetAdapterを呼び出すとフッターが表示されません)。削除せずにフッタービューの可視性を直接変更してしまいました。
DVDは

loadElements(currentPage)に何を追加する必要がありますか??? つまり、AsyncTaskまたはスレッドを呼び出すのですか?
android_developer 2013年

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、ユーザーが表示することは保証されていません。それは単にリストビュー測定のものかもしれません。
Thomas Ahle 2013

10個のアイテムをスクロールした後、さらに多くのアイテムをロードしたい。しかし、10番目のアイテムが表示される前に読み込みが開始されることに気づきました。9番目のアイテムです。これを停止する方法は?
Atul Bhardwaj 2012年

4

Ognyan Bankov GitHub私はシンプルで実用的な解決策を見つけました!

これによりVolley HTTP library、Androidアプリのネットワーキングがより簡単に、そして最も重要なことに、より高速になります。Volleyは、オープンAOSPリポジトリから入手できます。

与えられたコードは以下を示します:

  1. HTTPページ分割されたリクエストによって入力されるListView。
  2. NetworkImageViewの使用法。
  3. 先読みによる「エンドレス」リストビューのページネーション。

将来の一貫性のため、私はBankovのレポをフォークしました


2

これは、読み込み中にListViewの最後に読み込みビューを簡単に表示できるようにするソリューションです。

あなたはここでクラスを見ることができます:

https://github.com/Cyber​​Eagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/helper/ListViewWithLoadingIndicatorHelper.java- を使用できるようにするヘルパーSimpleListViewWithLoadingIndicatorから拡張しない機能。

https://github.com/Cyber​​Eagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/listener/EndlessScrollListener.java- ユーザーがデータのロードを開始するリスナーListViewの下部に到達しようとしています。

https://github.com/Cyber​​Eagle/OpenProjects/blob/master/android-projects/widgets/src/main/java/br/com/cybereagle/androidwidgets/view/SimpleListViewWithLoadingIndicator.java-The EndlessListView。このクラスは直接使用することも、拡張することもできます。


1

少し遅れる可能性がありますが、次の解決策は私の場合非常に役に立ちました。ある方法で行う必要があるのは、ListView aに追加して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");
    }
});

このイベントは、フッターが表示され、チャームのように機能するときに1回発生します。


0

この問題の重要な点は、load-moreイベントを検出し、データの非同期リクエストを開始して、リストを更新することです。また、ローディングインジケーターやその他のデコレーターを備えたアダプターも必要です。実際、問題はいくつかのまれなケースで非常に複雑です。OnScrollListenerアイテムが画面いっぱいに表示されない場合があるため、実装だけでは不十分です。

の無限リストをサポートする個人用パッケージを作成し、マルチページソースからデータを非常に簡単に取得できるRecyclerView非同期ローダー実装も提供していAutoPagerFragmentます。RecyclerView次のページだけでなく、カスタムイベントの任意のページを読み込むことができます。

ここにアドレスがあります:https : //github.com/SphiaTower/AutoPagerRecyclerManager


リンクが壊れています。
DSlomer64 2017


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

私はそれが古い質問であることを知っており、Androidの世界はほとんどRecyclerViewsに移行しましたが、興味のある人にとっては、このライブラリーが非常に興味深いと感じるかもしれません。

ListViewで使用されるBaseAdapterを使用して、リストが最後のアイテムにスクロールされたとき、または最後のアイテムから離れてスクロールされたときを検出します。

それは、それがどのように機能するかを素早く理解するために使用できるサンプルプロジェクト(ほとんど100行のActivityコード)が付属しています。

簡単な使い方:

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.