Arva Views are in essence Famo.us Views on famous-flex steroids. They allow us to easily create ES6 extendible views that can be inherited by other components.

Views are nodes in the rendering tree that can contain either famous Surfaces which correspond to actual DOM elements or other Views.

Let's dive into it! We'll demonstrate a short example to see how we can cook together some basic UI here.

The first View

The following snippet will give us a new View without anything displaying on screen.

import {View}               from 'arva-js/core/View.js';

export class HomeView extends View {
}

At your Surface!

Our next step is to add some content to our view. We do this by adding class properties containing either a Famo.us Surface or an Arva View instance. Layouting of these "renderables" is done with ES6 decorators.

import Surface              from 'famous/core/Surface.js';
import AnimationController  from 'famous-flex/AnimationController.js';
import {View}               from 'arva-js/core/View.js';
import {layout}             from 'arva-js/layout/decorators.js';

export class HomeView extends View {
    /* The size of this surface is 300x25 px */
    @layout.size(300, 25)
    /* Place it in the midddle of the view */
    @layout.place.center()
    /* Define an animation on creation */
    @layout.animate({
        animation: AnimationController.Animation.FadedZoom,
        transition: {duration: 200}
    })
   /* Initialize the surface itself */
    message = new Surface({
        /* The content of the surface */
        content: 'Hello world',
        /* CSS properties */
        properties: {
            textAlign: 'center',
            color: 'slategray'
        }
    });
}

In a similar fashion, we can also define a background for the view:

    /* Translate the element in z space to the back */
    @layout.translate(0, 0, -10)
    /* Make the element cover the entire space */
    @layout.fullSize()
    /* Definition of the element */
    background = new Surface({properties: {backgroundColor: 'aliceblue'}});

Extending one view with another

For some characteristic views, you might not feel like constantly reinventing the wheel. Let's define a general view with a top bar.

export class ViewWithTopBar extends View {
    /* Dock to the top with a 44px height */
    @layout.dock('top', 44)
    /* Define an animation on creation */
    @layout.animate({
        animation: AnimationController.Animation.Slide.Down,
        transition: {duration: 100}
    })
    /* Initialize the surface itself */
    topBar = new Surface({
        /* CSS properties */
        properties: {
            backgroundColor: 'teal'
        }
    });
}

Now, we can simply do HomeView extends ViewWithTopBar to get a top bar in the HomeView. Easy, right?

📘

Hint

To make the view appear less busy, you can let the animation in the HomeView wait for the top bar to finish. Just add a property waitFor: 'topBar' in the animation options of message and you're done.

Events

To listen for HTML events, the common on, off, and once are readily available. Let's define a surface that will only show once you click the Hello world text. We make event listeners in the constructor of the class, which we haven't defined just yet. Have a look at this:

    /* The size of this surface is 300x25 px */
    @layout.size(300, 25)
    /* Place it in the midddle of the view */
    @layout.place('center')
    /* Listen for click events to show the other Surface */
    @event.on('click', function(){this.showRenderable('answer');})
    /* Define an animation on creation */
    @layout.animate({
        animation: AnimationController.Animation.FadedRotateZoom,
        transition: {duration: 1000}
    })
   /* Initialize the surface itself */
    message = new Surface({
        /* The content of the surface */
        content: 'Hello world',
        /* CSS properties */
        properties: {
            textAlign: 'center',
            color: 'slategray'
        }
    });


    @layout.size(300, 25)
    /* Translate 100px below our main message */
    @layout.translate(0, 100, 0)
    @layout.animate({
        /* Hide initially */
        showInitially: false,
        /* Slide to the left in form the right */
        animation: AnimationController.Animation.Slide.Left,
        transition: {duration: 500}
    })
    @layout.place('center')
    answer = new Surface({content: 'Yes?', properties: {textAlign: 'center'}});
    
    

📘

Events bubble upwards

Events of a child will fire for the parent as well. This means that listening for clicks on the HomeView will trigger automatically when the message click is fired.

Putting it all together

Let's see how our code turned out in it's entire form:

import Surface              from 'famous/core/Surface.js';
import AnimationController  from 'famous-flex/AnimationController.js';
import {View}               from 'arva-js/core/View.js';
import {layout, event}   from 'arva-js/layout/decorators.js';


export class ViewWithTopBar extends View {
    /* Dock to the top with a 44px height */
    @layout.dock('top', 44)
    /* Place it in the midddle of the view */
    /* Define an animation on creation */
    @layout.animate({
        animation: AnimationController.Animation.Slide.Down,
        transition: {duration: 100}
    })
    /* Initialize the surface itself */
    topBar = new Surface({
        /* CSS properties */
        properties: {
            backgroundColor: 'teal'
        }
    });
}


export class HomeView extends ViewWithTopBar {
    /* The size of this surface is 300x25 px */
    @layout.size(300, 25)
    /* Place it in the midddle of the view */
    @layout.place('center')
    /* Define an animation on creation */
    @layout.animate({
        waitFor: 'topBar',
        animation: AnimationController.Animation.FadedRotateZoom,
        transition: {duration: 1000}
    })
    /* Listen for click events to show the other Surface */
    @event.on('click', function(){this.showRenderable('answer');})
   /* Initialize the surface itself */
    message = new Surface({
        /* The content of the surface */
        content: 'Hello world',
        /* CSS properties */
        properties: {
            textAlign: 'center',
            color: 'slategray'
        }
    });

    /* Translate the element in z space to the back */
    @layout.translate(0, 0, -10)
    /* Make the element cover the entire space */
    @layout.fullscreen
    /* Definition of the element */
    background = new Surface({properties: {backgroundColor: 'aliceblue'}});

    @layout.size(300, 25)
    /* Translate 100px below our main message */
    @layout.translate(0, 100, 0)
    @layout.animate({
        /* Hide initially */
        showInitially: false,
        /* Slide to the left in form the right */
        animation: AnimationController.Animation.Slide.Left,
        transition: {duration: 500}
    })
    @layout.place('center')
    answer = new Surface({content: 'Yes?', properties: {textAlign: 'center'}});

}

Sweetness, that was the tutorial so far. If you want to some more intricate control over your animations, or something more flashy, be sure to check out the flow section.