web-dev-qa-db-ja.com

ページネーション用のProgressBarを備えたEndless RecyclerView

RecyclerView を使用し、10個のバッチでAPIからオブジェクトをフェッチしています。ページネーションには、 EndlessRecyclerOnScrollListener を使用します。

すべて正常に動作しています。次は、APIによってオブジェクトの次のバッチが取得される間に、リストの下部に進行状況スピナーを追加するだけです。 Google Playストアアプリのスクリーンショットは、ProgressBarRecyclerViewが表示されています。

enter image description here

問題は、RecyclerViewEndlessRecyclerOnScrollListenerも、次のオブジェクトのバッチがフェッチされている間、下部にProgressBarを表示するための組み込みのサポートがないことです。

私はすでに次の答えを見てきました。

1。ProgressBar grid にフッターとして不定のRecyclerViewを挿入します。

2。下部のRecyclerViewでEndless Scroll ProgressBarにアイテムを追加する

私はそれらの答えに満足していません(両方とも同じ人による)。これには、ユーザーがスクロールしている途中でnullオブジェクトをデータセットにシューホーンし、次のバッチが配信された後にそれを取り出すことが含まれます。それはハックのように見え、適切に機能するかどうかわからない主要な問題を回避します。そして、それはリストにちょっとした不快感と歪みを引き起こします

SwipeRefreshLayout を使用することは、ここでは解決策ではありません。 SwipeRefreshLayoutは、先頭からプルしてnewestアイテムを取得することを伴いますが、いずれにしても進行状況ビューは表示されません。

誰かがこれに良い解決策を提供できますか? Googleが独自のアプリにこれをどのように実装しているかに興味があります(Gmailアプリにもあります)。これが詳細に示されている記事はありますか?すべての回答とコメントを歓迎します。ありがとうございました。

その他の参照

1。RecyclerView によるページネーション。 (素晴らしい概要...)

2。RecyclerViewヘッダーとフッター 。 (同じものをもっと...)

3。End of RecyclerView with bottomProgressBar with bottom

56
Y.S

HERE IS SIMPLER AND CLEANER APPROACH。

このコードパスガイド からエンドレススクロールを実装し、次の手順に従います。

1。 RecyclerViewの下にプログレスバーを追加します。

    <Android.support.v7.widget.RecyclerView
        Android:id="@+id/rv_movie_grid"
        Android:layout_width="0dp"
        Android:layout_height="0dp"
        Android:paddingBottom="50dp"
        Android:clipToPadding="false"
        Android:background="@Android:color/black"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

    </Android.support.v7.widget.RecyclerView>

    <ProgressBar
        Android:id="@+id/progressBar"
        style="?android:attr/progressBarStyle"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:visibility="invisible"
        Android:background="@Android:color/transparent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

ここでAndroid:paddingBottom = "50dp"およびAndroid:clipToPadding = "false"非常に重要です。

2。進行状況バーへの参照を取得します。

progressBar = findViewById(R.id.progressBar);

3。進行状況バーを表示および非表示にするメソッドを定義します。

void showProgressView() {
    progressBar.setVisibility(View.VISIBLE);
}

void hideProgressView() {
    progressBar.setVisibility(View.INVISIBLE);
}
15
Akshar Patel

これを行う別の方法があります。

  • まず、アダプターのgetItemCountがlistItems.size() + 1を返します
  • getItemViewType()position >= listItems.size()VIEW_TYPE_LOADINGを返します。これにより、ローダーはリサイクラビューリストの最後にのみ表示されます。このソリューションの唯一の問題は、最後のページに到達した後でもローダーが表示されるため、アダプターにx-pagination-total-countを保存することを修正するためです。
  • 次に、ビュータイプを返すように条件を変更します

    (position >= listItem.size())&&(listItem.size <= xPaginationTotalCount)

今このアイデアを思いついたのですが、どう思いますか?

5
Bhargav

ここに偽のアイテムを追加せずに回避策があります(Kotlinではシンプルですが):

アダプターに以下を追加します。

private var isLoading = false
private val VIEWTYPE_FORECAST = 1
private val VIEWTYPE_PROGRESS = 2

override fun getItemCount(): Int {
    if (isLoading)
        return items.size + 1
    else
        return items.size
}

override fun getItemViewType(position: Int): Int {
    if (position == items.size - 1 && isLoading)
        return VIEWTYPE_PROGRESS
    else
        return VIEWTYPE_FORECAST
}

override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): RecyclerView.ViewHolder {
    if (viewType == VIEWTYPE_FORECAST)
        return ForecastHolder(LayoutInflater.from(context).inflate(R.layout.item_forecast, parent, false))
    else
        return ProgressHolder(LayoutInflater.from(context).inflate(R.layout.item_progress, parent, false))
}

override fun onBindViewHolder(holder: RecyclerView.ViewHolder?, position: Int) {
    if (holder is ForecastHolder) {
        //init your item
    }
}

public fun showProgress() {
    isLoading = true
}


public fun hideProgress() {
    isLoading = false
}

これで、API呼び出しの前にshowProgress()を簡単に呼び出すことができます。およびhideProgress() AP​​I呼び出しが行われた後。

3
Amir Ziarati

進行状況ビューホルダーをアダプターに追加するというアイデアは気に入っていますが、必要なものを取得するためのsomeいロジック操作につながる傾向があります。ビューホルダーアプローチでは、getItemCount()getItemViewType()getItemId(position)およびあらゆる種類のgetItem(position)メソッドの戻り値を調整することにより、追加のフッターアイテムから保護する必要があります。含めたい。

別のアプローチは、ロードの開始時と終了時にそれぞれProgressBarの下にFragmentを表示または非表示にすることにより、ActivityまたはProgressBarレベルでRecyclerView可視性を管理することです。これは、ビューレイアウトにProgressBarを直接含めるか、カスタムRecyclerViewViewGroupクラスに追加することで実現できます。このソリューションは、通常、メンテナンスの削減とバグの削減につながります。

更新:コンテンツの読み込み中にビューを上にスクロールすると、私の提案に問題が生じます。 ProgressBarは、ビューレイアウトの下部に固定されます。これはおそらくあなたが望む動作ではありません。このため、進行状況ビューホルダーをアダプターに追加することが、おそらく最も優れた機能的なソリューションです。アイテムアクセサメソッドを保護することを忘れないでください。 :)

3
Ryan

このソリューションは、このページのAkshar Patelsソリューションに触発されています。少し修正しました。

  1. 最初の項目をロードするとき、ProgressBarを中央に配置すると良いように見えます。

  2. ロードするアイテムがなくなったときに下部にある空のパディングが気に入らなかった。このソリューションでは削除されました。

最初のXML:

<Android.support.v7.widget.RecyclerView
    Android:id="@+id/video_list"
    Android:paddingBottom="60dp"
    Android:clipToPadding="false"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent">

</Android.support.v7.widget.RecyclerView>

<ProgressBar
    Android:id="@+id/progressBar2"
    style="?android:attr/progressBarStyle"
    Android:layout_marginTop="10dp"
    Android:layout_width="wrap_content"
    Android:layout_centerHorizontal="true"
    Android:layout_height="wrap_content"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"/>

その後、次のプログラムを追加しました。

最初の結果がロードされたら、これをonScrollListenerに追加します。 ProgressBarを中央から下に移動します。

ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) loadingVideos.getLayoutParams();
layoutParams.topToTop = ConstraintLayout.LayoutParams.UNSET;
loadingVideos.setLayoutParams(layoutParams);

アイテムがなくなったら、次のように下部のパディングを削除します。

recyclerView.setPadding(0,0,0,0);

通常どおりProgressBarを非表示および表示します。

0
John T

次のように、recycleViewでlayout_aboveタグを使用できます。

<RelativeLayout
                    Android:layout_width="match_parent"
                    Android:layout_height="match_parent"
                    Android:layout_marginLeft="16dp"
                    Android:layout_marginRight="16dp"
                    Android:orientation="vertical">
                    <androidx.recyclerview.widget.RecyclerView
                        Android:id="@+id/rv"
                        Android:layout_below="@+id/tv2"
                        Android:layout_width="match_parent"
                        Android:focusable="false"
                        Android:layout_height="wrap_content"
                        Android:layout_marginTop="24dp"
                        Android:layout_above="@+id/pb_pagination"/>

                     <ProgressBar
                        Android:id="@+id/pb_pagination"
                        style="@style/Widget.AppCompat.ProgressBar"
                        Android:layout_width="30dp"
                        Android:layout_height="30dp"
                        Android:indeterminate="true"
                         Android:visibility="gone"
                        Android:layout_alignParentBottom="true"
                        Android:layout_centerHorizontal="true" />
    </RelativeLayout>
0
Houssin Boulla