Hanbit the Developer

[Kotlin] RecyclerView in SwipeRefreshLayout in NestedScrollView Implementation 본문

Mobile/Android

[Kotlin] RecyclerView in SwipeRefreshLayout in NestedScrollView Implementation

hanbikan 2021. 9. 24. 20:05

In my app, the layout structure is: NestedScrollView -> FrameLayout -> SwipeRefreshLayout -> RecyclerView

 

Before the explanation, see a video explaining it.

 

 

There are some points to implement it.

1. Add android:fillViewport="true" in NestedScrollView

This helps the child views fill the remaining space.

 

2. Set the views which moves smoothly according to gestures rather than treat the recycler view as a linear layout by adding android:nestedScrollingEnabled="false" into the recycler view.

Treating a recycler view as a linear layout is too bad for performance.

 

To implement it, you can write a function for it as below:

// You must declare isViewDetailed in Class like:
private var isViewDetailed: Boolean = true
private fun setViewsForDetail(flag: Boolean){
    isViewDetailed = flag

    if(isViewDetailed){
        yourView.visibility = View.VISIBLE
        binding.nestedScrollView.scrollTo(0, 0)
    }else{
        yourView.visibility = View.GONE
    }
}

 

Use it as setViewsForDetail(true) or setViewsForDetail(false).

 

Left side: isViewDetailed = true, Right side: isViewDetailed = false

You can use the function in 3. And as you might see, there is no animation yet, which I will explain.

 

 

3. Add a TouchListener on the recycler view.

private fun addListenerOnRecyclerView(){
        var x = 0f
        var y = 0f
        
        recyclerView.setOnTouchListener { v, event ->
            when (event.action){
                MotionEvent.ACTION_DOWN -> {
                    // Save a touch position
                    x = event.x
                    y = event.y
                    true
                }
                MotionEvent.ACTION_UP -> {
                    // OnClick
                    if(kotlin.math.abs(x - event.x) < 10 && kotlin.math.abs(y - event.y) < 10){
                        setViewsForDetail(!isViewDetailed)
                    }
                    // OnScrollDown
                    else if(y > event.y){
                        setViewsForDetail(false)
                    }
                    true
                }
            }

            v.performClick()
            v.onTouchEvent(event) ?: true
        }

        // When recycler view is on top
        recyclerView.setOnScrollChangeListener { _, _, _, _, _ ->
            if(!recyclerView.canScrollVertically(-1)){
                setViewsForDetail(true)
            }
        }
    }

The code looks long but, I just used setViewsForDetail() which we wrote. And there is some logic for catching gestures.

 

4. Add android:animateLayoutChanges="true" on parent views of changing views.

In my case, I added android:animateLayoutChanges="true" in constraint layout which contains:

As a result, when I call setViewsForDetail(false), finally the message box closed out with a animation!