Skip to content

Directional conversion system

Beka Westberg edited this page Dec 23, 2019 · 2 revisions

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:

And has methods to convert between them.

Movement direction

The movement direction is the direction the the user is moving in, not the direction the views are moving in.

Value

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.

Description

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.

Traversal direction

The traversal direction is the direction in which we are going through the child indices of the views.

Value

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.

Description

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.

Adapter direction

The adapter direction is the direction in which we are going through the adapter indices of the views.

Value

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.

Description

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.

Conversions

How to determine the movement direction

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.

Movement direction ⟷ Traversal direction

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.

Movement/Traversal direction ⟷ Adapter direction

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.