Views and screen
What you will learn
In this lesson, you will create a new button View
and a new Screen
from scratch. The new screen will have two “buttons”.
This should be the final result :
View overview
You previously worked in a file called LoaderView
that inherits from View
class. A View
is composed of primitives (like in LoaderView
) but can also be composed of other views. In short terms, View
elements are containers. They do not have any rendering, but allow you to manage groups of elements and re-use them wherever you want in your application. Moreover, View
have the capability to be focused and blurred.
Creating a “button” like View
New file creation
First of all, add new style property in your AppTheme
:
export default $AbstractTheme.declare("AppTheme", {
statics: {
COLOR_WHITE: "#FFFFFF",
COLOR_BLACK: "#000000",
COLOR_BLUE_LIGHT: "#00adec",
H2_FONT_SIZE: 35
}
});
Your ButtonView
will be composed of a TextPrimitive
and a RectanglePrimitive
.
Create a new file named ButtonView.js
in scripts/app/ui/views
with the following content :
import $View from "@View";
import $TextPrimitive from "@TextPrimitive";
import $RectanglePrimitive from "@RectanglePrimitive";
import $Theme from "@Theme";
/**
* Button
*
* @name ButtonView
* @class
* @extends View
*/
export default $View.declare("ButtonView", {
statics: /** @lends ButtonView */ {
HORIZONTAL_MARGIN: 20,
VERTICAL_MARGIN: 5,
TEXT_HEIGHT: 41
},
children: {
rectangle: {
class: $RectanglePrimitive
},
text: {
class: $TextPrimitive
}
},
style: {
width: ({text, statics}) => text.width + 2 * statics.HORIZONTAL_MARGIN,
height: ({statics}) => statics.TEXT_HEIGHT + 2 * statics.VERTICAL_MARGIN,
text: {
isAuto_width: true, // eslint-disable-line @dana/no-use-width-height-auto,
height: ({parent}) => parent.statics.TEXT_HEIGHT,
x: ({parent}) => parent.statics.HORIZONTAL_MARGIN,
y: ({parent}) => parent.statics.VERTICAL_MARGIN,
size: $Theme.H2_FONT_SIZE,
color: $Theme.COLOR_WHITE,
text: "Home"
},
rectangle: {
width: ({parent}) => parent.width,
height: ({parent}) => parent.statics.TEXT_HEIGHT + 2 * parent.statics.VERTICAL_MARGIN,
borderRadius: 12,
fillColor: $Theme.COLOR_BLUE_LIGHT
}
}
});
Adding it as a child of a screen
To see the button, you need to add it to a Screen
. Open SplashScreen
, add import of ButtonView
and add a new child called button
that is using your ButtonView
.
import $ButtonView from "@ButtonView";
export default $AppScreen.declare("SplashScreen", {
children: /** @lends SplashScreen.prototype */ {
button: {class: $ButtonView},
loader: {class: $LoaderView}
}
});
Refresh your page, and you will see your button appear in the top-left corner.
Allow text customization
Actually, text of your button is always “Hello”. Create a method in the ButtonView
to update text property of its child text
.
Caution
Keyword methods
allow to declare functions for your class.
export default $View.declare("ButtonView", {
methods: /** @lends ButtonView.prototype */ {
setText: function(text) {
this.text.text = text;
}
}
});
this.text
allows to access to your TextPrimitive
child named text
and this.text.text
allows you to access to the text
property of this textPrimitive
.
To see it in action, you need to use prepareData
method in SplahScreen
. Make a call on the button to setText
to be able to set a new text.
export default $AppScreen.declare("SplashScreen", {
methods: /** @lends SplashScreen.prototype */ {
connectData: function () {
this.button.setText("Hello World");
}
}
});
Once validated, remove the import, the child and the call to setText
from your SplashScreen
because you are going to create a new screen dedicated for this button.
Screen overview
The class Screen
inherits from class View
. So yes, a screen is a view and has the same purpose to group elements. But screens can do more than views. Screens will be responsible to manage user interactions, collect datas, listen to events… It controls inputs and events.
When creating TV applications, it is common to talk about screens as it is common to talk about pages on a website. It is important to organise a complete application between multiple screens.
Allow text customization
Create a new Screen
Create a new file named CatalogScreen.js
in scripts/app/ui/screens
with the following content :
import $AppScreen from "@AppScreen";
import $ButtonView from "@ButtonView";
/**
* Catalog
*
* @name CatalogScreen
* @class
* @extends AppScreen
* @screen
*/
export default $AppScreen.declare("CatalogScreen", {
children: /** @lends CatalogScreen.prototype */ {
button: {class: $ButtonView}
},
methods: /** @lends CatalogScreen.prototype */ {
//////////////////////////////////////////////////////////////////////////////////////////
// EXTENSION POINTS
//////////////////////////////////////////////////////////////////////////////////////////
/**
* Prepare screen data: get the business data to feed the views
* View should always be full filled with business model(s).
*
* It must returns a Object.
*
* @param {Object} [context] The context shared by the screens during display
* @returns {Promise<Object,Error>} returns a promise resolved with the data
* @override
*/
prepareData: function (context) {
return Promise.resolve({});
},
/**
* Connect the data prepared by {@link prepareData} to the views.
* Use the data property, which is the return value of {@link prepareData}.
*
* @param {Object} [context] The context shared by the screens during display
* @override
*/
connectData: function (context) {
this.button.setText("Hello World");
}
}
});
For now, this screen is mainly filled with nothing, but it has your ButtonView
as a child. And that’s all you need for the begining of this screen.
To be able to display a screen, you need to register a route. Give a name to the route matching the screen name, like for example catalog
.
Open {appName}AppRoutes
file. There is already an import of SplashScreen
and a route named splash
that displays the SplashScreen
. Do the same for your catalog.
import $AbstractAppRoutes from "@AbstractAppRoutes";
import $SplashScreen from "@SplashScreen";
import $CatalogScreen from "@CatalogScreen";
/**
*
* @name TemplateAppRoutes
* @class
* @extends AbstractAppRoutes
* @implementation
* @routes splash
* @routes catalog
*/
export default $AbstractAppRoutes.declare("TemplateAppRoutes", {
methods: /** @lends TemplateAppRoutes.prototype */ {
splash: function (data) {
return $SplashScreen.display(data);
},
catalog: function (data) {
return $CatalogScreen.display(data);
}
}
});
To display the new screen instead of the splash screen, you can change the first route of you project by using profiles. In app.config.json
, inside the object default
, you will find a key named firstRoute
. Update it with your catalog
:
"firstRoute": {
"id": "catalog"
}
Caution
Changes in profiles are not hot reloaded. When updating your profiles, you will need to kill your npm start
command and restart it.
You now should see your new screen with your button in the top left corner.
Summary
To summarize, during this lesson you have :
- created a
View
and aScreen
- updated a child from screen it belongs to
To go further on those concepts, you can browse the following documentation pages :