Skip to content

Instantly share code, notes, and snippets.

@danaimset
Created May 14, 2018 19:10
Show Gist options
  • Star 20 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save danaimset/abacaa50d746a4537686a08ecc33c1a9 to your computer and use it in GitHub Desktop.
Save danaimset/abacaa50d746a4537686a08ecc33c1a9 to your computer and use it in GitHub Desktop.
package com.danaimset.widget
import android.content.Context
import android.support.v4.widget.NestedScrollView
import android.support.v7.widget.RecyclerView
import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup
open class SmartNestedScrollView(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : NestedScrollView(context, attrs, defStyleAttr) {
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(context: Context) : this(context, null)
override fun measureChildWithMargins(child: View?, parentWidthMeasureSpec: Int, widthUsed: Int, parentHeightMeasureSpec: Int, heightUsed: Int) {
if (findNestedRecyclerView(child) != null) {
val lp = child?.layoutParams as ViewGroup.MarginLayoutParams
val childHeightMeasureSpec = View.MeasureSpec.makeMeasureSpec(
lp.topMargin + lp.bottomMargin, View.MeasureSpec.AT_MOST)
child.measure(parentWidthMeasureSpec, childHeightMeasureSpec)
} else {
super.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed)
}
}
private fun findNestedRecyclerView(view: View?): RecyclerView? {
when (view) {
is RecyclerView -> return view
is ViewGroup -> {
var index = 0
do {
val child = view.getChildAt(index)
val recyclerView = findNestedRecyclerView(child)
if (recyclerView == null) {
index += 1
} else {
return recyclerView
}
} while (index < view.childCount)
}
else -> return null
}
return null
}
}
@danaimset
Copy link
Author

Firstly, thanks for answering ;)
But I don't see how the layout would prevent from loading all items at once since it uses the (normal) NestedScrollView even with Paging ...

It seems impossible to make it working without multiple scroll delegates. While recycler view will not reach the top of the scrollable parent it should be scrolled by using scrollview. As soon as RecyclerView is at the top of sv: RecyclerView scroll take a place.
But for now I'm using Epoxy by AirBnb

@kroegerama
Copy link

Here is another approach, wich will also allow horizontal RecyclerViews and only does its magic for vertical RecyclerViews:

import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup
import androidx.core.view.forEach
import androidx.core.widget.NestedScrollView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView

open class SmartNestedScrollView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : NestedScrollView(context, attrs, defStyleAttr) {

    override fun measureChildWithMargins(child: View, parentWidthMeasureSpec: Int, widthUsed: Int, parentHeightMeasureSpec: Int, heightUsed: Int) {
        if (findNestedRecyclerView(child) != null) {
            val lp = child.layoutParams as MarginLayoutParams
            val childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
                lp.topMargin + lp.bottomMargin, MeasureSpec.AT_MOST
            )
            child.measure(parentWidthMeasureSpec, childHeightMeasureSpec)
        } else {
            super.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed)
        }
    }

    private fun findNestedRecyclerView(view: View): RecyclerView? {
        if (view is RecyclerView) {
            val vertical = (view.layoutManager as? LinearLayoutManager)?.orientation == LinearLayoutManager.VERTICAL
            if (vertical) return view
        }

        if (view is ViewGroup) {
            view.forEach { child ->
                val rv = findNestedRecyclerView(child)
                if (rv != null) return rv
            }
        }

        return null
    }
}

@bineeshbabu
Copy link

Hey there!
Make sure that RecyclerView is keeping it's height as wrap_content and don't constraint it to the bottom of the parent container.
If you need more details, please let me know and I'll share my latest layout with the same issue (Scrollable RecyclerView only)

Cool one. works fine.

@nayan-dhabarde
Copy link

nayan-dhabarde commented Jul 20, 2022

<com.awantunai.app.custom.SmartNestedScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="@id/layoutSkuCategory"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
>

<com.awantunai.app.component.HorizontalSkuList
android:id="@+id/horizontalSkuList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/layoutSkuCategory"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvSku"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/at_medium"
android:orientation="vertical"
android:scrollbars="none"
android:nestedScrollingEnabled="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/horizontalSkuList"
tools:listitem="@layout/item_cart_layout" />

</com.awantunai.app.custom.SmartNestedScrollView>

This is my layout, I still face the same problem of infinite loading

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment