リストの最後に到達したときに通知されるようにリストを作成して、さらにアイテムをロードするにはどうすればよいですか?
リストの最後に到達したときに通知されるようにリストを作成して、さらにアイテムをロードするにはどうすればよいですか?
回答:
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データの読み込みなど)には個別のスレッドを使用する必要があり、最後のリストアイテム(marketまたはgmailアプリのように)の進行状況を示したい場合があります。
firstVisible + visibleCount >= totalCount
、リスナーへの複数の呼び出しで条件が複数回満たされることです。load-more関数がWebリクエストである場合(ほとんどの場合はそうです)、リクエストが実行されているかどうかのチェックを追加します。一方、リスト内の同じ数のアイテムに対して複数のリクエストを行う必要がないため、totalCountが前の合計カウントと等しくないかどうかを確認します。
私が自分のアプリに使用したソリューションを提供したかっただけです。
これもOnScrollListener
インターフェースに基づいていますが、スクロール操作中に表示/合計数の計算が実行されないため、ローエンドデバイスでのスクロールパフォーマンスがはるかに優れていることがわかりました。
ListFragment
かListActivity
実装してみましょうOnScrollListener
そのクラスに次のメソッドを追加します。
@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
場合にロードプロセスをトリガーする(最後から数えた)リストアイテムの数です。たとえばに設定threshold
し0
た場合、より多くのアイテムをロードするために、ユーザーはリストの最後までスクロールする必要があります。
(オプション)ご覧のとおり、「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>
(オプション)最後に、listView.removeFooterView(yourFooterView)
アイテムまたはページがなくなった場合に呼び出して、ロードインジケーターを削除します。
ListFragment
問題なくそれを使っています-上記の各手順に従ってください、あなたは大丈夫です;)それともエラーメッセージを提供できますか?
getListView().setOnScrollListener(this)
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で実行する必要があります)
getView
です。たとえばpos
、ユーザーが表示することは保証されていません。それは単にリストビュー測定のものかもしれません。
でOgnyan Bankov GitHub
私はシンプルで実用的な解決策を見つけました!
これによりVolley HTTP library
、Androidアプリのネットワーキングがより簡単に、そして最も重要なことに、より高速になります。Volleyは、オープンAOSPリポジトリから入手できます。
与えられたコードは以下を示します:
将来の一貫性のため、私はBankovのレポをフォークしました。
これは、読み込み中に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-The EndlessListView。このクラスは直接使用することも、拡張することもできます。
少し遅れる可能性がありますが、次の解決策は私の場合非常に役に立ちました。ある方法で行う必要があるのは、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回発生します。
この問題の重要な点は、load-moreイベントを検出し、データの非同期リクエストを開始して、リストを更新することです。また、ローディングインジケーターやその他のデコレーターを備えたアダプターも必要です。実際、問題はいくつかのまれなケースで非常に複雑です。OnScrollListener
アイテムが画面いっぱいに表示されない場合があるため、実装だけでは不十分です。
の無限リストをサポートする個人用パッケージを作成し、マルチページソースからデータを非常に簡単に取得できるRecyclerView
非同期ローダー実装も提供していAutoPagerFragment
ます。RecyclerView
次のページだけでなく、カスタムイベントの任意のページを読み込むことができます。
ここにアドレスがあります:https : //github.com/SphiaTower/AutoPagerRecyclerManager
これまで見てきた最善の解決策は、リサイクラービューのFastAdapterライブラリにあります。それは持っていますEndlessRecyclerOnScrollListener
。
次に使用例を示します。EndlessScrollListActivity
無限のスクロールリストに使用すると、セットアップが非常に堅牢であることがわかりました。私は間違いなくそれをお勧めします。
私はそれに非常に似た別のソリューションで作業していますが、を使用し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) {
}
});
私はそれが古い質問であることを知っており、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に作成し、上記のアダプターコードに示すように配置するだけです。
楽しい。