A pull to refresh you can call your own

Written by qwerty.ayush5 | Published 2018/05/22
Tech Story Tags: android-app-development | kotlin | custom-views

TLDRvia the TL;DR App

Introduced in 22.1.0, the SwipeToRefreshLayout has become a staple in many modern Android apps. This is my attempt at creating a simple SwipeToRefreshLayout clone utilizing the ValueAnimator and the Android Touch Framework.

Lets first summarize the two functions from the Android touch framework used in this tutorial : onInterceptTouchEvent and onTouchEvent.

  • onInterceptTouchEvent allows a viewgroup to “intercept” a touch event and decide whether to pass it on to its child or consume the event for itself. Hence, this function is a part of the ViewGroup and not View.
  • onTouchEvent is present in both the View and ViewGroup class. In the Viewgroup class, this function is only called when the parent decides not to pass on the touch event to its children (i.e it passes true on onInterceptTouchEvent). In the child, however, this is called when the child receives the touch event from its parent.

This flow of filtering a touch event from the parent to the child can be used to create a very rudimentary pull to refresh view seen in many apps.

Our custom pull to refresh works as follows :

If the user scrolls down on a scrollable view (RecycleView for instance) refreshing the view is not required. Hence, the parent ViewGroup is not interested in the touch event and passes it to the child. (onInterceptTouchEvent = false).

If however, the user scrolls up, our scenario bifurcates into two. The first and simpler scenario is that the user is has not reached the top of the recycleview and thus we do not need the “refresh view”. (onInterceptTouchEvent = false).

The second scenario is when the user has reached the top and tries to scroll up further. This will trigger the refresh view to appear. Thus for this case only, the parent is interested in the touch event and does not pass it on to its child and instead triggers its own onTouchEvent. (onInterceptTouchEvent = true).

Without further ado, lets jump into the nitty-gritty shall we.

First lets create the skeleton of a custom Pull to refresh parent.

For any basic pull to refresh pattern, the parent (in this case : AnimatedPullToRefreshLayout) must determine if the scroll able child is currently at the top or not. The easiest way to determine this is to attach a scrollListener to the child in the onLayout callback of the parent

The setOnScrollListener is used to set onTopReached which represents the state of the child (whether it is at the top or in some other position).

However, attaching a scrollListener per se is not enough because onTopReached is also used in onInterceptTouchEvent and once it is set as true in onScrollListener, onInterceptTouchEvent will not let the touch event be propagated to the child. Hence, we must also track the y coordinate of the touch event as well.

In cases where the parent decides to handle the touchEvent, onTouchEvent will be triggered in the parent. onTouchEvent is responsible for presenting custom pull to refresh logic.

In the ACTION_MOVE event of the preceding codeblock, increasing the top margin of the child view reveals the “refresh view” in the lower layer of the framelayout. The refresh view must be retracted when the user releases their finger from the device or when the background task that triggers the refresh logic in the UI thread has completed. (API calls for instance).

The xml used in the app :

Here’s a little demo to blow you away. Enjoy!

I hope you enjoyed my take on a custom pull to refresh view. I hope to see you next time around.


Published by HackerNoon on 2018/05/22