---
layout: default
---


* TOC
{:toc}


# How to turn the PPS for a Scroll bar into code

The code implementation should spiritually follow the PPS; that is, your code should only take
action when moving from state to state (along the arrows in the PPS). This behavior is best
represented by a `switch` statement, where each `case` represents a state in our PPS. Within each
`case`, there can be nested `if` statement to handle transitioning to another state.

Each `case` should be broken out of and should properly handle input, propagating input to later
views or stopping the input propagation as necessary. We typically do this through the
`onTouchEvent` method. In `onTouchEvent`, returning `true` will stop the input propagation
to views below it, while returning `false` allows views below it to handle the event.

## Volume example

<div class="mermaid">
graph LR
S((.)) --> A((Start))
A -- "Press:insideBar? A" --> I((Inside))
I -- "Release:B" --> E[End]
I -- "Drag:insideBar? C" --> I
I -- "Drag:outsideBar? D" --> I

classDef finish outline-style:double,fill:#d1e0e0,stroke:#333,stroke-width:2px;
classDef normal fill:#e6f3ff,stroke:#333,stroke-width:2px;
classDef start fill:#d1e0e0,stroke:#333,stroke-width:4px;
classDef invisible fill:#FFFFFF,stroke:#FFFFFF,color:#FFFFFF

class S invisible
class A start
class E finish
class I normal

</div>

where
- A is updateVolume();updateThumbPosition();updateThumbAlpha();
- B is updateThumbAlpha();invokeVolumeChangeListeners()
- C is updateVolume();updateThumbPosition();invalidate()
- D is doNothing()

```java
@Override
public boolean onTouchEvent(MotionEvent event) {
    EssentialGeometry geometry = essentialGeometry(event);
    switch(mState) {
        case START:
            if (event.getAction() == MotionEvent.ACTION_DOWN && geometry == EssentialGeometry.BAR) {
                mState = State.INSIDE;
                updateThumbPosition();
                updateThumbAlpha();
                updateVolume();
                invalidate();
                return true;
            }
            break;
        case INSIDE:
            if (event.getAction() == MotionEvent.ACTION_MOVE && geometry == EssentialGeometry.BAR) {
                updateThumbPosition();
                updateVolume();                
                invalidate();
                return true;
            } else if (event.getAction() == MotionEvent.ACTION_UP) {
                mState = State.START;
                updateThumbAlpha();
                invokeVolumeChangeListener();
                invalidate();
                return true;                   
            }
            break;
        default:
            break;
    }
    return false;
}
```
In the above code snippet, `updateThumb()` would handle determining and setting the opacity of the
thumb, while `updateVolume()` would similarly update the volume based on the position of your finger.
Function calls inside the switch cases should be used to break up the logic in complicated situations
or where the same logic can be used for multiple transitions.