web-dev-qa-db-ja.com

Android無限リスト

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

231
Isaac Waller

1つの解決策は、 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;
        }
    }
}

実行時間の長いアクション(Webデータの読み込みなど)には別個のスレッドを使用する必要があり、最後のリストアイテム(マーケットやGmailアプリのように)の進行状況を表示することもできます。

268
Josef Pfleger

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

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

  1. ListFragmentまたはListActivityOnScrollListenerを実装させます
  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. (オプション)ご覧のとおり、「ロードモアチェック」はユーザーがスクロールを停止したときにのみ呼び出されます。使いやすさを向上させるために、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)を呼び出してそのロードインジケータを削除します。

94
saschoar

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

20

Ognyan Bankov GitHub で、シンプルで実用的なソリューションが見つかりました!

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

指定されたコードは以下を示します。

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

将来の一貫性のためにi Bankovのレポを分岐

4
oikonomopo

読み込み中に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 - EndlessListView。このクラスを直接使用することも、そこから拡張することもできます。

2

少し遅れるかもしれませんが、私の場合、次の解決策が非常に役立ちました。必要なのは、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");
    }
});

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

1
tehcpu

私がこれまで見た中での最良の解決策は、リサイクラーのビュー用の FastAdapter ライブラリです。 EndlessRecyclerOnScrollListener があります。

以下に使用例を示します。 EndlessScrollListActivity

無限のスクロールリストに使用すると、セットアップが非常に堅牢であることがわかりました。絶対お勧めします。

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
pabloverd

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

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にボタンを作成し、上記のアダプターコードに示すように配置するだけです。

楽しい。

0
gbenroscience

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

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

アドレスは次のとおりです。 https://github.com/SphiaTower/AutoPagerRecyclerManager

0
ProtossShuttle