Article in Code Manual category.

Magic Touch Recycler

We have all been wowed and frustrated by the recycler view animations at some point in our lives or you will be if not yet.…

We have all been wowed and frustrated by the recycler view animations at some point in our lives or you will be if not yet. 😛 Most of the time, it's about adding an animation while loading data or animating an item on tap. Our design team at Fueled came up with something different. 

Let's have a look at what we wanted to achieve:

The problem statement: Scale up the currently focused recycler item and keep it as is unless the focus moves to the next item or the user lifts their finger up; Scale down the previously focused item as soon the user moves on to the next item. Sounds pretty straight forward right?  But wait, Recyclerview needs to scroll as well when the user just slides their finger quickly—which is the tricky part.

Let’s see how we achieved this behavior:

Recyclerview’s addOnItemTouchListener allows you to add an OnItemTouchListener to intercept touch events before they are dispatched to child views. Bingo! That’s precisely what we need.

So let’s create our ScaleItemOnTouchListener which extends RecyclerView.OnItemTouchListener 

classScaleItemOnTouchListener : RecyclerView.OnItemTouchListener {

    .......

overridefunonInterceptTouchEvent(rv: RecyclerView, event: MotionEvent): Boolean {
        var interceptTouch = false
        when (event.actionMasked) {
            MotionEvent.ACTION_DOWN -> {
                previousMotionX = event.x
                previousMotionY = event.y
            }
            MotionEvent.ACTION_MOVE -> {
                interceptTouch = !(abs(event.x - previousMotionX) > DRAG_THRESHOLD ||
                    abs(event.y - previousMotionY) > DRAG_THRESHOLD)
            }
            MotionEvent.ACTION_UP -> {
                previousMotionX = 0f
                previousMotionY = 0f
            }
        }
   
        return interceptTouch
    }
   
    ........
   
}

Now we can control when to invoke onTouchEvent based on the value of boolean returned by onInterceptTouchEvent. We want to invoke scrolling only when the user just slightly glides their finger on the list and scaling only when they focus on a particular item and then starts dragging the finger around without lifting it up from the screen. We use the drag threshold constant, to differentiate between these two behaviors.

Now let’s take a look at what happens when onTouchEvent gets invoked:

classScaleItemOnTouchListener : RecyclerView.OnItemTouchListener {
        overridefunonTouchEvent(rv: RecyclerView, event: MotionEvent) {

        val childView = rv.findChildViewUnder(event.x, event.y)
        val previousChild = rv.findChildViewUnder(previousX, previousY)
        if (childView != null) {
            when (event.action) {
                MotionEvent.ACTION_DOWN, MotionEvent.ACTION_MOVE -> {
                    if (childView.scaleX != SCALE_UP) {
                        scaleUp(childView)
                    }

                    if (previousChild != null && previousChild != childView) {
                        scaleDown(previousChild)
                    }
                }
                MotionEvent.ACTION_UP, MotionEvent.ACTION_POINTER_UP -> {
                    scaleDown(childView)
                    childView.callOnClick()
                }
            }
            previousX = childView.x
            previousY = childView.y
        } elseif (previousChild != null && (event.action == MotionEvent.ACTION_UP
                || event.action == MotionEvent.ACTION_CANCEL)) {
            scaleDown(previousChild)
            previousX = 0f
            previousY = 0f
        }
    }
   
    .......
}

We want to scale down the item that the user was previously touching and at the same time scale up the new item that they are currently touching. The amazing findChildViewUnder method comes to our rescue here. You can check out the complete code here.

Bingo! That’s all the pieces we wanted to put into play at the right motion events. 

Thanks for sticking around and happy coding!

More Articles By bhavya

Recent Articles

Previous post Tangerine is Your Necessary Dose of Self-Care May 26, 2021
Next post Pride Counseling makes getting help easy for the LGBTQ community June 2, 2021