简体   繁体   English

当我的列表到达底部的recyclerview时,如何显示进度条?

[英]How to show progress bar when my list reaches the bottom recyclerview?

I have created stmth like buggy paging library and when I reach the bottom of list I would like to show progress bar before my data will be downloaded. 我创建了错误的页面库之类的stmth,当我到达列表的底部时,我想在下载数据之前显示进度栏。 I think that notifyItemInserted() will help me bu I don't understand where I have to insert this item. 我认为notifyItemInserted()可以帮助我,但我不知道我必须在何处插入该项目。 I think that I have to use notifyItemChanged also for hiding all data fields and show progress bar at my list item. 我认为我还必须使用notifyItemChanged隐藏所有数据字段并在列表项中显示进度栏。 So, here is my own loading additional data when I reach the end of list: 因此,当我到达列表末尾时,这是我自己加载的其他数据:

 jobLst.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                if (dy > 0) {
                    val visibleItemCount = mLayoutManager.childCount
                    val totalItemCount = mLayoutManager.itemCount
                    val pastVisibleItems = mLayoutManager.findFirstVisibleItemPosition()
                    if (loading) {
                        if (visibleItemCount + pastVisibleItems >= totalItemCount && !recyclerView.canScrollVertically(1)) {
                 // here I would like to show loader

getJobList(Integer.parseInt(Uri.parse(nextUrl).getQueryParameter("offset")), type, sp.getString("access_token", ""), filterData, true) 
                        }
                    }
                }
            }
        })

and I think that I will have to change my item layout: 而且我认为我将不得不更改项目布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginStart="15dp"
    android:layout_marginTop="4dp"
    android:layout_marginEnd="15dp"
    android:background="@drawable/message_list_item_bg"
    android:orientation="vertical">


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="10dp"
        android:layout_marginTop="5dp"
        android:layout_marginEnd="10dp"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/tv_job_title"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="3.5"
            android:ellipsize="end"
            android:fontFamily="@font/opensans_semibold"
            android:singleLine="true"
            android:textColor="#333333"
            app:autoSizeMaxTextSize="20sp"
            app:autoSizeMinTextSize="8sp"
            app:autoSizeStepGranularity="2sp"
            app:autoSizeTextType="uniform" />

        <TextView
            android:id="@+id/tv_date"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="0.5"
            android:fontFamily="@font/opensans_semibold"
            android:gravity="end"
            android:textSize="12sp" />

    </LinearLayout>

    <TextView
        android:id="@+id/tv_address"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="10dp"
        android:layout_marginTop="5dp"
        android:layout_marginEnd="10dp"
        android:ellipsize="end"
        android:fontFamily="@font/opensans_regular"
        android:gravity="center_vertical"
        android:singleLine="true"
        android:textColor="#999999"
        app:autoSizeMaxTextSize="20sp"
        app:autoSizeMinTextSize="8sp"
        app:autoSizeStepGranularity="2sp"
        app:autoSizeTextType="uniform" />


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="10dp"
        android:layout_marginTop="5dp"
        android:layout_marginEnd="10dp"
        android:orientation="horizontal"
        tools:ignore="UseCompoundDrawables">

        <TextView
            android:id="@+id/tv_company"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginEnd="30dp"
            android:layout_weight="3.5"
            android:ellipsize="end"
            android:fontFamily="@font/opensans_regular"
            android:gravity="center_vertical"
            android:singleLine="true"
            android:textColor="#666666"
            app:autoSizeMaxTextSize="20sp"
            app:autoSizeMinTextSize="8sp"
            app:autoSizeStepGranularity="2sp"
            app:autoSizeTextType="uniform" />


        <ImageView
            android:id="@+id/add_to_notepad"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/add_to_notepad"
            android:gravity="end" />


        <ProgressBar
            android:id="@+id/progressBar"
            android:layout_width="24dp"
            android:layout_height="24dp"
            android:gravity="end"
            android:visibility="gone" />
    </LinearLayout>


</LinearLayout>

current progressbar is already used and can't be used for this purpose. 当前进度条已被使用,不能用于此目的。 So, I will need to add and then remove one item with another view type before and after loading some new data.My main layout: 因此,在加载一些新数据之前和之后,我将需要添加然后删除具有另一种视图类型的项。我的主要布局是:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white"
    tools:context=".jobAGENT.JobsList">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="75dp"
        android:gravity="center_horizontal"
        android:text="@string/no_jobs"
        android:textSize="32sp"
        android:textStyle="italic"
        android:visibility="gone" />

    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/refresh_t"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginStart="5dp"
        android:layout_marginTop="10dp"
        android:layout_marginBottom="5dp"
        android:background="@color/white">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/job_list_t"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginStart="10dp"
            android:layout_marginTop="10dp"
            android:layout_marginEnd="10dp"
            android:layout_marginBottom="10dp" />


    </android.support.v4.widget.SwipeRefreshLayout>


</FrameLayout>

So, what you can advice me? 那么,您能给我什么建议?

Use the below code snippet

<androidx.recyclerview.widget.RecyclerView
            android:id="@+id/rcylv"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginTop="@dimen/dimen_5dp"/>


    <ProgressBar
            android:id="@+id/progressBar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:scaleX="3"
            android:scaleY="3"
            android:visibility="gone"/>

 And inside activity

 jobLst.addOnScrollListener(object : RecyclerView.OnScrollListener() {
        override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
            if (dy > 0) {
                val visibleItemCount = mLayoutManager.childCount
                val totalItemCount = mLayoutManager.itemCount
                val pastVisibleItems = mLayoutManager.findFirstVisibleItemPosition()
                if (loading) {
                    if (visibleItemCount + pastVisibleItems >= totalItemCount && !recyclerView.canScrollVertically(1)) {
             progressBar.visibility = View.VISIBLE -> Kotlin
                       or
             progressBar.setVisibility(View.VISIBLE); -> Java

                    }
                }
            }
        }
    })

In your Adapter add this.. 在您的适配器中添加此。

        @Override
    public void onBindViewHolder(ViewHolder viewHolder, int i) {
        if(i==list.size()){
            //show your progress bar
        }
}

You can add a special loading ViewHolder type for your RecyclerView Adapter and keep the special item at the last one. 您可以为RecyclerView Adapter添加特殊的加载ViewHolder类型,并将特殊项保留在最后一个。

The loading ViewHolder item layout just include a ProgressBar . 正在加载的ViewHolder项布局仅包含一个ProgressBar

This special item resolution has an advantage is that you can easily use the RecyclerView Animation when show or hide loading item. 这种特殊的项目分辨率的优点是,当显示或隐藏正在加载的项目时,您可以轻松地使用RecyclerView动画。

|=== normal item ====|
|=== normal item ====|
|=== normal item ====|
|=== normal item ====|
|=== normal item ====|
--- insert data here ----
|=== loading item ===|

Here is the Adapter demo code, i didn't run the demo but it is enough to show the idea. 这是Adapter演示代码,我没有运行演示,但足以说明这个想法。

class ListAdapter(list: List<ItemModel>) : RecyclerView.Adapter<ListAdapter.BaseItemHolder>() {

    companion object {
        private const val VIEW_TYPE_LOADING = 1
        private const val VIEW_TYPE_NORMAL = 2
    }
    private var mList = list
    private var mShowLoading = false

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseItemHolder {
          when(viewType) {
              VIEW_TYPE_NORMAL -> return NormalViewHolder.create(parent)
              VIEW_TYPE_LOADING -> return LoadingViewHolder.create(parent)
          }
        return BaseItemHolder(parent)
    }

    override fun getItemCount(): Int {
         // return data list size + loading item size
        return mList.size + if (mShowLoading) { 1 } else { 0 }
    }

    override fun onBindViewHolder(holder: BaseItemHolder, position: Int) {
        if (holder is NormalViewHolder) {
            holder.bind(mList[position])
        } else if (holder is LoadingViewHolder) {
            //do nothing
            //LoadingViewHolder does not need bind data
        }
    }

    override fun getItemViewType(position: Int): Int {
        if (position < mList.size) {
            return VIEW_TYPE_NORMAL
        }
        return VIEW_TYPE_LOADING
    }

    fun hideLoading() {
        mShowLoading = false
        //be careful with the index
        notifyItemRemoved(itemCount)
    }

    fun showLoading() {
        mShowLoading = true
        //be careful with the index
        notifyItemInserted(itemCount - 1)
    }


    open class BaseItemHolder(itemView: View) : RecyclerView.ViewHolder(itemView)

    class LoadingViewHolder(itemView: View) : BaseItemHolder(itemView) {

        private var mText: TextView = itemView.findViewById(R.id.item_title)

        companion object {
            fun create(parent: ViewGroup): LoadingViewHolder {
                //R.layout.layout_loading_item just contain a progress bar or something like that
                return LoadingViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.layout_loading_item, parent, false))
            }
        }

        // LoadingViewHolder does not need bind data
        //fun bind() {
        //  
        //}

    }

    class NormalViewHolder(itemView: View) : BaseItemHolder(itemView) {

        private var mText: TextView = itemView.findViewById(R.id.item_title)

        companion object {
            fun create(parent: ViewGroup): NormalViewHolder {
                return NormalViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.layout_list_item, parent, false))
            }
        }

        fun bind(itemModel: ItemModel) {
            //bind your data with ItemModel data
        }

    }
} 

It seems like I have managed to solve my problem by the easiest way. 看来我已经设法通过最简单的方法解决了我的问题。 At main layout where RecyclerView is placed you have to add your ProgressBar which will be below RV and for this purpose you have to use Relative layout. 在放置RecyclerView的主布局中,您必须添加进度栏,该进度条将位于RV下面,并且为此,您必须使用相对布局。 Then you can use scrollListener for recyclerview like this: 然后,您可以像下面那样将scrollListener用于recyclerview:

recyclerview.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                    if (!recyclerView.canScrollVertically(1)) {
                        loader.visibility = View.VISIBLE
                    }else{
                        loader.visibility = View.GONE
                    }
                }
            }


        })

and when your response will be successful you will hide your progress bar. 当您的响应成功后,您将隐藏进度栏。 Maybe it will help someone else except me :) 也许它将帮助我以外的其他人:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM