简体   繁体   中英

Unable to scroll to item in RecyclerView that is inside NestedScrollView

I'm trying to programmatically scroll to a particular item within my RecyclerView which is nested within a NestedScrollView.

The Problem

The NestedScrollView scrolls to the complete bottom rather than the desired item.
Note: It works correctly when desired item is the 2nd item, probably since that item is visible in the screen.

What I've tried

I've searched through a dozen solutions from StackOverFlow and came up with the function below.
I've tried:

  • binding.variantsRecyclerView.getChildAt()
  • binding.variantsRecyclerView.findViewWithTag()
  • binding.variantsRecyclerView.findViewHolderForAdapterPosition()

All these do return the correct item, (I know since the edit text within that item is focused as coded) however, the NestedScrollView does not scroll correctly to that item. It is almost always scrolling to the bottom. Sometimes however it scrolls to somewhere in between the required item instead of it's start. The only time this works is when the item is either the 1st or 2nd item. (As stated before)

private fun scrollToPosition(position: Int) {
        if (position in 0 until variantsAdapter.itemCount) {
            val view = binding.variantsRecyclerView.findViewWithTag<ConstraintLayout>("pos_$position")
            if (view != null) {
                val height = binding.nestedScrollView.height
                val target = view.y.toInt()
                binding.nestedScrollView.postDelayed({
                    binding.nestedScrollView.smoothScrollTo(0, target)
                    view.requestFocus()
                }, 200)
            }
        }
    }

My XML

<?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"
    android:background="#eff1f4">


    <LinearLayout>...</LinearLayout>

    <androidx.core.widget.NestedScrollView
        android:id="@+id/nestedScrollView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:fillViewport="true"
        app:layout_constrainedHeight="true"
        app:layout_constraintVertical_bias="0"
        app:layout_constraintBottom_toTopOf="@+id/btnNextLayout"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/toolbarLayout">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginStart="@dimen/ui_10_dp"
            android:layout_marginEnd="@dimen/ui_10_dp"
            android:orientation="vertical">

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/variantsRecyclerView"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:clipToPadding="false"
                android:nestedScrollingEnabled="false"
                android:paddingTop="12dp"
                android:paddingBottom="12dp"
                app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
                tools:itemCount="2"
                tools:listitem="@layout/sell_variant_row_item" />

            <androidx.constraintlayout.widget.ConstraintLayout>
             ...
            </androidx.constraintlayout.widget.ConstraintLayout>

        </LinearLayout>

    </androidx.core.widget.NestedScrollView>

    <LinearLayout>...</LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

My Understanding

After debugging, I found out that the NestedScrollView height is lesser than the y co-ordinate of the desired item. Hence it scrolls to the bottom of the view instead of the desired item. My understanding could be completely wrong and if so, please correct me.

I resolved this with a really simple fix.

private fun scrollToPosition(position: Int) {
    if (position in 0 until variantsAdapter.itemCount) {
        val view = binding.variantsRecyclerView.getChildAt(position)
        if (view != null) {
            val target = binding.variantsRecyclerView.top + view.top
            binding.nestedScrollView.scrollY = target 
        }
    }
}

All I wanted was to get the desired item within the RecyclerView to the top of the screen.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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