Mastering ViewPager with Directed Acyclic Graph
Edit: Checkout new NavigationArchitecture Component that was released recently.
Ever thought of using Directed Acyclic Graph (DAG) with ViewPager
? Its a perfect combination.
What is Directed Acyclic Graph?
DAG is just a graph where every edge goes forward i.e. there are no cycles.
Why use DAG?
ViewPager
is the most commonly used view when dealing with flows. Almost every app has some sort of account creation or onboarding flow for new users. Or may be your app requires that user answers a few questions before you can create a specialized experience for them e.g. news or magazine apps. Or it could simply be that your app heavily relies on survey forms/questionnaires that your users fill to receive rewards.
One other simple and common use case for ViewPager
is to show tabs which we are not interested in for this article.
If you want to create a truly dynamic flow which changes based on previous answers, as user fills out your form, then DAG is a must use data structure, otherwise your code will become unmanageable. If we let nodes in DAG to represent Fragment
then you can easily see how flexible your ViewPager
becomes. You can take any route during flow and can change next node based on previous answers. And it only needs to work in forward direction because, for reverse, ViewPager
will just backtrack the steps.
DAG is so useful that I wonder why android does not support a
DAGViewPagerAdapter
natively!
Sample:
Before we start, we need an implementation of Directed Acyclic Graph. In Android, DAG is required when you are building ScriptGroup
, as mentioned in ScriptGroup.Builder
’s documentation. Another interesting place where DAG is being used is in CoordinatorLayout
. For our implementation we will borrow it, as its not a public class.
Here is how Node
looks like:
PageDescriptor
is required to instantiate our fragments as we are using cwac-pager adapter.NodeSelector
is what we use to decide whether we want to move to this node or not. First we create all of our nodes with appropriate selectors, this process can be static or dynamic based on your requirements.
NodeSelector
implementation to detect kids:
Once we have all the nodes, we can build our DAG:
Or you can roll your own fluent DAG Builder. Following is an example of a static flow that we have in one of our app:
Once your graph is ready, you can start your flow from root node by showing it:
From that point on whenever you want to go to next node, you ask DAG for all outgoing edges from current node and use the selector to pick appropriate node:
Handling Back Button
If the user goes back and changes his choice, we want to update the flow bundle and also remove that PageDescriptor
from our adapter. We can’t do that as soon as back button is pressed because it will mess up back animation of ViewPager
so instead we only cleanup our adapter lazily when going forward:
Now our flow can easily switch path based on answer
You can even combine several DAGs or handle complex scenarios where answer of 5th question invalidates answer of 3rd question, which 6th question was dependent on! Of course you can still use DAG if your flow is a simple straight line.
Next read:
Resources:
Another attempt at this by Santi Aguilera:
If you have a better way to implement this flow, share it in the comments or create a pull request. Feel free to ask any question and suggest topics which you think I should write on in the future.