Android Kotlin开发RecyclerView的OnScrollListener不触发问题咨询
RecyclerView OnScrollListener不生效的原因及解决方案
核心原因
- 你把
RecyclerView嵌套在了NestedScrollView内部,滚动事件会被外层的NestedScrollView优先消费,RecyclerView本身接收不到滚动事件,自然不会触发OnScrollListener回调。 - 你的
RecyclerView在NestedScrollView中设置layout_height="match_parent"实际是无效的,会被解析为自适应内容高度,当前只有1条未占满全屏的条目时,RecyclerView本身不存在滚动空间,也不会触发滚动回调。 - 额外问题:你当前的代码每次调用
assignResponseToRecyclerview都会重复初始化LayoutManager、Adapter和滚动监听,属于不合理的冗余逻辑,也可能导致监听异常。
解决方案
方案1:移除多余的NestedScrollView(推荐)
如果你的业务不需要嵌套滚动能力,直接删掉外层的NestedScrollView标签,让RecyclerView作为ConstraintLayout的直接子控件即可,修改后的布局核心代码如下:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout 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="match_parent" tools:context=".view.MainActivity"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/rv_api_response" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginStart="8dp" android:layout_marginLeft="8dp" android:layout_marginTop="8dp" android:layout_marginEnd="8dp" android:layout_marginRight="8dp" android:layout_marginBottom="8dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"/> <ProgressBar android:id="@+id/progress_bar" android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="visible" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
同时优化Kotlin代码中重复初始化的问题,把RecyclerView的初始化、滚动监听设置都移到onCreate中,后续请求到数据只更新数据源刷新列表即可:
class MainActivity : AppCompatActivity() { lateinit var restModel : RestModel var apiResponseList : MutableList<ApiResponse> = arrayListOf() lateinit var itemAdapter: ItemAdapter var handler: Handler = Handler() lateinit var layoutManager : LinearLayoutManager lateinit var mainPresenter: MainPresenter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.main_activity) mainPresenter = MainPresenter(this) // 只初始化一次RecyclerView相关配置 layoutManager = LinearLayoutManager(this) itemAdapter = ItemAdapter(apiResponseList) rv_api_response.apply { layoutManager = this@MainActivity.layoutManager adapter = itemAdapter addOnScrollListener(object : RecyclerView.OnScrollListener() { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { super.onScrolled(recyclerView, dx, dy) Log.e("z","z") } }) } val currentDate = mainPresenter.convertDate() mainPresenter.makeACall(currentDate) } override fun assignResponseToRecyclerview(apiResponse: ApiResponse?) { apiResponse?.let { apiResponseList.add(it) itemAdapter.notifyDataSetChanged() } } }
方案2:保留NestedScrollView的处理方式
如果业务必须保留外层的NestedScrollView,就需要给RecyclerView关闭嵌套滚动,转而监听NestedScrollView的滚动事件:
- 给RecyclerView添加属性
android:nestedScrollingEnabled="false",或者在代码中调用rv_api_response.isNestedScrollingEnabled = false - 给NestedScrollView设置id,比如
android:id="@+id/nested_scroll_view",然后监听它的滚动回调即可。
内容的提问来源于stack exchange,提问作者user21597761
相关产品推荐
相关产品推荐

