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
}
}
@ruthwikkk
Copy link

How can I achieve something like this?
-SmartNestedScrollView
----Reletive/Linear/ConstrinedLayout
--------View
--------RecyclerView

when I try to implement such a layout, only recycler view is scrollable. I want to scroll the view and recycler view as whole

@Vnicius
Copy link

Vnicius commented Sep 11, 2019

I'm have the same issue @ruthwikwarrier

@danaimset
Copy link
Author

danaimset commented Sep 11, 2019

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)

@Vnicius
Copy link

Vnicius commented Sep 12, 2019

I have the layout like @ruthwikwarrier

-SmartNestedScrollView
----LinearLayout
--------LinearLayout
--------RecyclerView

The RecyclerView already has the height as wrap_content

@vkay94
Copy link

vkay94 commented Sep 12, 2019

@danaimset
It would be nice if you share the layout. I'm also facing the issue like the others.

@danaimset
Copy link
Author

danaimset commented Sep 13, 2019

This one works for me:
https://gist.github.com/danaimset/da40360f0d5fee88c1bcf7fc6aea0268

If you're not using paging library then probably you don't need SmartNestedScrollView actually

@vkay94
Copy link

vkay94 commented Sep 13, 2019

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 ...

@danaimset
Copy link
Author

Well, while you're using RecyclerView inside another scrollable container you should firstly double check if you're able to put all page content inside single RecyclerView, like headers or so.
Epoxy provides great implementations that may help you.
Share your layout to have a chance to try it.

@joye-wang
Copy link

joye-wang commented Sep 29, 2019

Sorry, The code doesn't work for me. Only the recyclerview is scrollable.
I paste my layout in here : https://pastebin.com/Q5xyiaWg

It looks like:

LinearLayout
    SmartNestedScrollView
        some view...
        RecyclerView
    EditText

Thank you for your time

@danaimset
Copy link
Author

Its late reply but it seems that
nestedScrollingEnabled = true for Recyclers
is missing in your recycler view

@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