Skip to content

Instantly share code, notes, and snippets.

@NielsMasdorp
Created November 22, 2018 12:05
Show Gist options
  • Save NielsMasdorp/c45199398ef5adc2f49b32dded93967f to your computer and use it in GitHub Desktop.
Save NielsMasdorp/c45199398ef5adc2f49b32dded93967f to your computer and use it in GitHub Desktop.
AppBarLayout that sets elevation when scrolling view is scrolling and no elevation when scrolling view is at the top
/**
 * [AppBarLayout] that monitors behavior of a scrolling view in the same layout and changes elevation on its Toolbar
 *
 * Usage:
 *
 * <ElevationAppBarLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:elevation="0dp"
    app:scrollingView="@id/recyclerView"/>
 *
 * Currently supports [RecyclerView] and [NestedScrollView]
 */
class ElevationAppBarLayout @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : AppBarLayout(context, attrs) {

    @IdRes
    private var attachedScrollerId: Int = 0

    init {
        attrs?.let {
            val typedArray = context.obtainStyledAttributes(it,
                    R.styleable.ScrollingAwareAppBarLayout, 0, 0)
            attachedScrollerId = typedArray.getResourceId(R.styleable.ScrollingAwareAppBarLayout_scrollingView, 0)
            typedArray.recycle()
        }
    }

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
        if (attachedScrollerId != 0) {
            val connectedView: View = rootView.findViewById(attachedScrollerId)
            if (connectedView is RecyclerView || connectedView is NestedScrollView) {
                monitorScroll(connectedView)
            } else {
                throw IllegalStateException("You can only attach a RecyclerView or NestedScrollView to your ScrollingAwareAppBarLayout!")
            }
        } else {
            throw IllegalStateException("You should attach a scrollable view to your ScrollingAwareAppBarLayout!")
        }
    }

    private fun monitorScroll(scroller: View) {
        when (scroller) {
            is RecyclerView -> {
                scroller.addOnScrollListener(object : RecyclerView.OnScrollListener() {
                    override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                        elevation = if (!scroller.canScrollVertically(-1)) {
                            0f
                        } else {
                            dimen(R.dimen.shadow_height).toFloat()
                        }
                    }

                    override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                        // No op
                    }
                })
            }
            is NestedScrollView -> {
                scroller.setOnScrollChangeListener { _: NestedScrollView, _: Int, scrollY: Int, _: Int, _: Int ->
                    elevation = if (scrollY == 0) {
                        0f
                    } else {
                        dimen(R.dimen.shadow_height).toFloat()
                    }
                }
            }
        }
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment