Directional conversion system
All LayoutManagers have to deal with different direction types (and conversions between them) if they want to properly support multiple orientations (e.g. reversable layouts, Horizontal and Vertical, or RTL mode). This page documents how the LoopingLayoutManager solves these problems.
The LoopingLayoutManager integrates the following direction types:
-
Movement direction
The direction the user is moving in. -
Traversal direction
The direction we are going through the child indices of the views in. -
Adapter direction
The direction we are going through the adapter indices of the views in.
And has methods to convert between them.
The movement direction is the direction the the user is moving in, not the direction the views are moving in.
The movement direction is described as either of the following:
-
TOWARDS_TOP_LEFT
Has a value of -1. -
TOWARDS_BOTTOM_RIGHT
Has a value of +1.
Note: TOWARDS_TOP_LEFT
doesn't mean the user is moving towards the top-left it means they are moving towards the top/left. That is, if the movement direction is TOWARDS_TOP_LEFT
in vertical mode, the user is moving towards the towards the top. If the movement direction is TOWARDS_TOP_LEFT
in horizontal mode, the user is moving towards the left.
The difference between the direction views are moving in, and the direction the user is moving in is best illustrated by this gif:
As you can see, the individual views are moving towards the left, but the user is trying to see new views at the right of the list. That is why the movement is described as TOWARDS_BOTTOM_RIGHT
.
The traversal direction is the direction in which we are going through the child indices of the views.
The traversal direction is described as either of the following:
-
TOWARDS_LOWER_INDICES
Has a value of -1. -
TOWARDS_HIGHER_INDICES
Has a value of +1.
Each view in a LayoutManager has two indices, it's child index, and its adapter index.
The child index has to do with the view's position on screen. The view in the top/left -most position always has a child index of 0
. The view in the bottom/right -most position always has a child index of childCount - 1
. At least for linear layouts like this project.
This is important because the LayoutManager can only loop through views based on their child index. Sometimes you want to loop through them from 0 -> (childCount - 1)
(towards higher) and sometimes you want to loop through them from (childCount - 1) -> 0
(towards lower). Those options are what the traversal direction describes.
The adapter direction is the direction in which we are going through the adapter indices of the views.
The adapter direction is described as either of the following:
-
TOWARDS_LOWER_INDICES
Has a value of -1. -
TOWARDS_HIGHER_INDICES
Has a value of +1.
As mentioned above, each child view has an adapter index in addition to its child index. The adapter index tells us which piece of adapter data the view is associated with. It has nothing to do with the position of the view.
You can't loop through views by adapter index directly, but sometimes you want to pass around a value describing which way you would like to loop through them. Either 0 -> (state.itemCount - 1)
(towards higher) or (state.itemCount - 1) -> 0
(towards lower). Those options are what the adapter direction describes.
The movement direction is found by taking the sign of the scroll delta, e.g. signum(delta)
. If the sign is positive, that means the user wants to see new views at the bottom/right of the layout. If the sign is negative, that means the user wants to see new views at the top/left of the layout.
I'm going to let you in on a secret, the movement direction and the traversal direction are actually the same thing.
If the user is moving towards the bottom/right that means new views would have a higher child index (i.e. TOWARDS_HIGHER_INDICES
). If the user is moving towards the top/left that means new views would have a lower child index (i.e. TOWARDS_LOWER_INDICES
). Always, no matter what.
This is because the lowest child index is always at the top/left and the highest child index is always at the bottom/right.
Sadly working with adapter indices/directions is not so simple. The relationship between the adapter directions and the movement/traversal directions is dependent on many things.
Because of this we need methods to convert between the directions. If you are working outside of the LoopingLayoutManager class you can use:
convertMovementDirToAdapterDir
convertAdapterDirToMovementDir
If you are working inside of it you can use:
getAdapterDirectionFromMovementDirection
getMovementDirectionFromAdapterDirection
These functions perform their logic based on two things, whether the layout is reversed or not, and whether it is LTR or RTL.
For example in your vanilla horizontal layout (i.e. not reversed and LTR) all of your directions are the same.
But if we reverse the layout, that's not the case.
Note: Just because all of your directions are the same it doesn't mean that the child index and adapter index are the same. The top/left -most view could have an adapter index of 3 while maintaining its child index of 0.