0

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.

General Grievance
  • 4,555
  • 31
  • 31
  • 45
rdias002
  • 214
  • 2
  • 9

1 Answers1

2

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.

rdias002
  • 214
  • 2
  • 9
  • Seems like a good solution, but what if you want to position nested scroll view on y = 0 and recycler view item to certain position. Still finding solution to this case. – I.Step Oct 17 '22 at 16:25