How to make the first app
Prerequisite: Take a look at Get Started post. It about how to install Jive.
Throughout this tutorial, we’ll walk you through the creation of a basic Jive application with a bit of animation.
Here is the video demonstration how our app will work.
Download the source code from jive-examples github repository. And go to the heart directory.
The app can be run using the command line below.
Project structure
The heart project has got 4 files inside. See it below. Let’s explain what they are.
- view
- MainWindow.xml (the view)
- viewmodel
- MainViewModel.hx (the view model)
- Application.hx (the start point)
- project.xml (the project file)
A Jive project is an OpenFL and Haxe project. So it must have a main class and project.xml as a project file.
To enable Jive library for the project we need a line below in project.xml
Start point
First of all our application needs a start point. It’s the Application class.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
package ;
import view.MainWindow;
import viewmodel.MainViewModel;
import jive.*;
class Application {
public function new() {
Jive.start();
var w: MainWindow = new MainWindow();
w.dataContext = new MainViewModel();
w.opened = true;
}
}
The Application constructor only
- initializes Jive;
- creates and opens the main Jive window;
- creates the main view model.
Here we need to pause and have a bit of information about Model-View-ViewModel concept and how it works for Jive.
MVVM idea
Jive is based on:
the Model - View - ViewModel idea.
MVVM facilitates a separation of development of the graphical user interface (a markup language or GUI code) from development of the business logic (the data model). The view model of MVVM is a value converter; meaning the view model is responsible for exposing (converting) the data objects from the model in such a way objects are easily managed and presented.
In this respect, the view model is more model than view, and handles most if not all of the view’s display logic.
and the Data Binding. It’s a way to implement a link between views and view models.
So for our app we need and it’s enough:
- a main view; It contains all graphics and layout it.
- a main view model. It handle the whole behavior (animation).
View
All views in Jive are Components. The important parts of Component’s interface are below.
1
2
3
4
5
6
7
8
class Component {
public var x: Metric;
public var y: Metric;
public var width: Metric;
public var height: Metric;
public var margin: MetricInsets;
public var parent: Container;
}
As a main view we use Window.
The window component is a root UI container for Jive application. We extend it using a declarative way. The MainView.xml is below.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8"?>
<Window
xmlns="jive"
xmlns:geom="jive.geom"
xmlns:haxe="http://haxe.org/"
width="{Binding windowWidth}"
height="{Binding windowHeight}">
<haxe:Implements>
<![CDATA[
jive.DataContextControllable<viewmodel.MainViewModel>
]]>
</haxe:Implements>
...
</Window>
Several points about semantics:
- the file name means the class name the file declares;
- the first tag name is the class name it extends;
- namespaces’re used to define Haxe packages;
- the information about “http://haxe.org/” namespace can be found on the HML library page;
- the interface jive.DataContextControllable
means that the MainWindow can only take MainViewModel objects as a ViewModel (dataContext property). - width={Binding windowWidth} means that the width property of the Window is binded to the windowWidth property of the MainViewModel.
The last point needs more detailed explanation.
View Model and Bindings
In our app we have the MainViewModel. You can see a part of it below. This viewmodel has a field windowWidth and the MainView binds it to the width property of the Window object. It means that when the value of MainViewModel.windowWidth is changed the Window.width will be changed to the new value as well.
1
2
3
4
5
6
7
8
9
10
package viewmodel;
import jive.geom.Metric;
@:bindable
class MainViewModel extends jive.ViewModel {
public var windowWidth: Metric;
public var windowHeight: Metric;
...
}
There are three modes of a binding:
- once {Binding property mode=once} The value of viewmodel property goes to the view only once when View.dataContext property is set.
- oneway {Binding property mode=oneway} The value of viewmodel property goes to the view everytime it’s changed. But if the value of a view property is changed it doesn’t go to a view model.
- twoway {Binding property mode=twoway} It’s the case when all changes go from a viewmodel to a view and from a view to a viewmodel.
View: Svg
The graphics container in Jive is the Svg component:
1
2
3
class Svg extends Component {
public var content: String;
}
The content property is the pure SVG content.
The example from our app View with Svg component inside.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<Svg
x="Metric.percent(50)"
y="Metric.percent(20)"
width="Metric.absolute(600)"
height="Metric.absolute(600)"
rotationAngle="{Binding rotation}"
rotationPivot="new IntPoint(0, 450)">
<content>
<rect
x="{rectX}"
y="{rectY}"
width="{rectSize}"
height="{rectSize}"
stroke="{strokeColor}"
stroke-width="1"
fill="none"
opacity="{rectAlpha}"/>
...
</content>
</Svg>
As you can see the SVG content also supports bindings to a view model.
Note: any change of a property binded to the SVG content causes the repaint of whole SVG component.
Moreover the SVG content has several special expression to define sizes.
- absolute(value) means Metric.absolute(value);
- virtual(value) means Metric.virtual(value);
- widthPercent(value) means Metric.percent(value) and the base it the width of the current SVG component;
- heightPercent(value) means Metric.percent(value) and the base it the height of the current SVG component.
Example:
1
2
3
4
5
6
7
8
9
10
<Svg>
<content>
<rect
x="{ absolute(50) }"
y="{ virtual(50) }"
width="{ widthPercent(100) }"
height="{ heightPercent(100) }"
fill="#ff0000"/>
</content>
</Svg>
Coordinates and sizes: absolute, virtual, percent
All coordinates and sizes of them have type Metric:
1
2
3
4
5
6
enum Metric {
absolute(value: Int);
virtual(value: Int);
percent(value: Float);
none;
}
- absolute means that value is a number of pixels.
- virtual means that value is a number of virtual pixels depending on the PPI of a display.
- percent means that the real value of the size will be calculated basing on the parent size.
Action
Let’s add some action to our app.
We’ve got a rect, two circles and a heart in our MainView. The Actuate library is good to animate our graphics via changing the values of our view model properties.
Firstly, place the figures to start positions in the MainViewModel constructor.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var stageW: Int = Std.int(Lib.current.stage.stageWidth);
windowWidth = Metric.absolute(stageW);
windowHeight = Metric.absolute(Std.int(Lib.current.stage.stageHeight));
rectSize = 300;
rectX = 0;
rectY = 150;
strokeColor = Color.LIGHT_GRAY.toSvg();
radius = 150;
circle1X = circle2X = Std.int(rectX + rectSize/2);
circle1Y = circle2Y = Std.int(rectY + rectSize/2);
rotation = 0.0;
rectAlpha = 0.0;
circleAlpha = 0.0;
heartAlpha = 0.0;
heartBorderAlpha = 0.0;
Then we show the rect via changing its opacity.
1
2
3
4
5
6
7
8
9
private function showRect() {
Actuate.tween(this, 1, {
rectAlpha: 1.0
})
.ease(Linear.easeNone)
.onComplete(function() {
showCircles();
});
}
So we’re just changing the rectAlpha property of the view model that is binded to the opacity attribute of SVG content. It causes redrawing of the SVG content and a user can see the visual animation.
Note: It’s not the best way to animate because of redrawing of whole SVG content but it’s only a demonstration of the Jive features.
I suggest downloading the jive-examples project (if it haven’t been happened yet) and running the Jive heart.