Search code examples
androidandroid-layoutuser-interfacekotlinandroidx

ItemTouchHelper scroll doesn't work in recyclerView that is nested in a horizontal Scroll view


I have a horizontal recyclerView in a LinearLayout in a fragment of its own. The placeholder for the fragment is wrapped in a horizontalScrollView. When i add in the fragment the recyclerview nestedScroll is set to false and the HorizontalScrollView controls the scroll fine.

However, i have now implemented ItemTouchHelper.Callback on the recyclerview to be able to reorder the cells. However when i move a cell out of the screen it doesn't scroll with it. I've tried changing nestedScroll and fixedSize but nothing is working.

I can't use a NestedScrollView as the recyclerView is horizontal correct?

Any advice

main xml

        <HorizontalScrollView
            android:id="@+id/timeline_horizontal_scroll_view"
            style="@style/timeline_horizontal_scroll_view_style">

            <FrameLayout
                android:id="@+id/media_scrub_placeholder"
                style="@style/media_scrub_placeholder_style" />
        </HorizontalScrollView>

fragment xml

<LinearLayout 
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/timeline_recycler_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</LinearLayout>

Solution

  • I was able to solve this using this in my fragment

    reorderTimelineRecyclerView.layoutManager = LinearLayoutManager(context!!, LinearLayoutManager.HORIZONTAL, false)
    reorderTimelineRecyclerView.isNestedScrollingEnabled = true
    broadcastScrollState(true, context!!)
    val callback = SimpleItemTouchHelperCallback(adapter, context!!, listOfLocalAssets.size)
    val touchHelper = ItemTouchHelper(callback)
    touchHelper.attachToRecyclerView(reorderTimelineRecyclerView)
    

    The broadcastScrollState updates the scroll of the recycler view to be enabled when in the reorder state and toggles it off after. So when the user long presses, it uses the scroll of the rcecyclerview but when not long pressing it uses the scroll of the horizontal scroll view. Hope this helps someone!

    EDIT

    fun broadcastScrollState(scrollState: Boolean, context: Context) {
        val intent = Intent("scroll-state-event")
        intent.putExtra("scroll-state", scrollState)
        LocalBroadcastManager.getInstance(context!!).sendBroadcast(intent)
    }
    

    And then in my fragment with the recycerlview I observe the internet and toggle the scroll state of my scrollview

    private val scrollReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            updateScrollState(intent!!.getBooleanExtra("scroll-state", false))
        }
    }
    
    private fun updateScrollState(scrollState: Boolean) {
        timeline_horizontal_scroll_view.isEnabled = !scrollState
    }