Upload
todd-anglin
View
774
Download
3
Embed Size (px)
Citation preview
NativeScriptCross-platform mobile apps with JavaScript
Todd Anglin@toddanglin
Burke Holland@burkeholland
Workshop Agenda
• Intro to NativeScript• NativeScript core concepts• “Hello World”• Defining Views• Debugging JavaScript• Basic data binding• Styling views with CSS
• Intro to Angular 2 concepts• Angular 2 + NativeScript• Navigating views• BONUS
• Extending with plugins• Adding animations• Using Telerik Platform
Ante Meridiem (9AM to Noon) Post Meridiem (1PM to 4PM)
Intro to NativeScript”How did we get here?”
2013 2014 2015 2016 2017
Early prototypes
“Core” engineering
Public launch
Adoption ramp-up
Mass adoption
Project Timeline
Delivering on the overdue promise of
“hybrid.”
Swift/Obj-C Java .NET
Mobile WebHybridNative
("1st Gen" x-plat native)
We ❤Web.But…
We need:• Better offline support• Access to device APIs• Home screen icons• Push notifications• App monetization• …
Hybrid Promise
100% Web
100% NativeHybrid
ReachCode/Skill Reuse
RichnessPremium experience
Device APIs
Best of both?
Hybrid Reality
80% coded 20%remaining
80% of dev time
Hybrid Reality
80% coded 20%remaining
80% of dev time 80% of dev time
Hybrid Reality
Hybrid "Peak"
Hybrid Promise
100% Web
100% NativeHybrid
ReachCode/Skill Reuse
RichnessPremium experience
Device APIs
Compromises
Binary Choice
NativeHybrid
😎 Best experience🐢 One platform at a time
🔥 Fast to market😭 Compromise on UX
Binary Choice
NativeHybrid
🔥 Fast to market😎 Best experience
JavaScript-driven native
🔥 Fast to market😎 Best experience
"Hybrid"Web UI with limited access to
native APIsNative App Shell
WebViewPlugins Plugins
Entire app lives here
Native App
"JavaScript-driven Native"Native UI driven by JavaScript
Native UI
JavaScript-to-Native bridge
JavaScript Engine(Your app code runs here)
Native APIs
NativeScript(by Telerik)
React Native(by Facebook)
“JavaScript-drive Native”
Native App
Native UI
JavaScript-to-Native runtime
JavaScript Engine(Your app code runs here)
Native APIs
Native App
Native UI
JavaScript Engine(Your app code runs here)
Native APIsAPI
WrapperAPI
Wrapper
PluginsPlugins
API Wrapper
API Wrapper
API Wrapper
API Wrapper
Plugins created with JS/TypeScript Plugins created with native code
“JavaScript-driven Native”
• Share code• Reuse existing skills/teams• Reuse existing libraries
• Native UI (no WebView!)• Full access to device APIs• Immediate access to new OS
features
🔥 Fast to market😎 Best experience
What is NativeScript?
• Open source framework (ASLv2)• Create native mobile apps for iOS, Android
(and eventually Windows 10)• Use JavaScript (“web skills”)• Write once, run everywhere
• Share 100% code between iOS/Android• Share 80% code with web
• Reuse popular plugins from NodeJS/iOS/Android
• Integrates deeply with Angular and TypeScript
With NativeScript…
• No web views (platform native UI)• Use JavaScript (or TypeScript)• 100% access to ALL native APIs (even new APIs)• Made for “web developers” (JS, CSS, XML)• Use Angular for web AND native mobile• Reuse thousands of libraries from
Node/iOS/Android/Web
The {N} difference…
Demo available in the app stores in May
Rich, animated, “no compromise” native UI(with shared UI code)
1
Measurable native UI performance(“no jank”)
2
Maximum code and skill reusability
3
Video credit: Nathan Walker, {N} community member
How does NativeScript work?Under the covers
Generated at build time for OS & 3rd party
native libraries
NativeScript Android example
output:
JavaScript
NativeScript iOS example
JavaScript
Runs on V8 JavaScript VM
Runs on JavaScriptCore VM
NativeScript Module Layer (NML)
• Abstractions on native APIs that provide unified, cross-platform API
• Dozens available out of the box• Easy for developers to add• IMPORTANT: All native APIs still available at JavaScript layer for platform-specific
scenarios
• NativeScript modules follow Node module’s conventions (CommonJS).
Example: NativeScript file module
Putting it all together
Style with CSSDefine UI with XML Logic with JavaScript
“Hello World”
Two ways to use NativeScript
1)
2)
Command Line Interface (CLI)
• Use Command Prompt (Win) or Terminal (Mac, Linux)
• Free, Part of open source project
• Requires installation, local environment setup to build for iOS/Android (requires Mac for iOS)
• Integrates with Visual Studio Code (via plugin)
WHY: More control, Free, Integrate with existing IDEs/code editors
WHO: More technical developers used to using CLI, Open source developers
Telerik Platform
• Use AppBuilder or Screen Builder• Subscription required
• Build in the cloud (no local install required)
• Easiest way to get started
WHY: Richer tooling, Easier setup, Platform integrated
WHO: Less technical developers, Prefer Platform integrations, Windows developers targeting iOS
Telerik PlatformPowerful visual tooling, cloud builds and
more for NativeScript app developers.
NativeScript CLI requirements
https://github.com/nativescript/nativescript-cli#system-requirements
Xcode, Xcode CLI tools, iOS SDK
JDK, Apache Ant, Android SDK
$ tns doctor
Choice in Architecture
JavaScriptWrite your application using plain JavaScript
TypeScriptUse TypeScript to get
Object Oriented features and compile time error
checking
AngularUse Angular to architect
application. Reuse almost all code between web and
mobile
Angular & TypeScript
• Created by Google• Open source• Popular JavaScript framework
for building complex web apps• “Angular 2” ships in May
• Created by Microsoft• Open source• Popular compiler for JavaScript that
adds powerful language features• Used to create Angular 2 and {N}
Starting a new project
{demo}
Running on iOS
or$ tns emulate ios
Running on Android
or$ tns emulate android
A better Android emulator
Visual Studio Android Emulator
Genymotion
NativeScript LiveSync$ tns livesync //For all connected devices/emulators
$ tns livesync android //Target specific platform
$ tns livesync ios --emulator
$ tns livesync ios --emulator --watch
• Refresh app with latest changes to JS, CSS, XML
• No re-build• Works with
emulators AND device
app.js
Defining Views
Pages
• XML markup structure• Elements (e.g. <Page>, <Label>) are
NativeScript modules
LayoutsUI Elements
Layouts
Absolute Dock Grid Stack Wrap
UI Widgets
• Button• Label• TextField• TextView• SearchBar• Switch• Slider• Progress• ActivityIndicator• Image
• ListView• HtmlView• WebView• TabView• SegmentedBar• DatePicker• TimePicker• ListPicker• Dialogs
Out-of-the-boxNative UI widgetsmeans…• Native behavior• Native perf• Native accessibility• Parity with “native”
Native UI widgets
Native API
{N} Module button
android.widget.Button UIButton
Label
TextField
Repeater
SegmentedBar
GridLayout
GridLayout
Label TextField
StackLayout
{demo}
Targeting Views• Target based on:
• screens size• minWH<X>, minW<X>, minH<X>
• platform• ios, android, windows
• Orientation• land, port
<file-name>[.<qualifier>]*.<extension>
styles.android.cssstyles.ios.css
mypage.minWH600.xmlmypage.xml
TIP• Platform specific capabilities are always available
• JavaScript: <view>.android or <view>.ios• Markup: <android></android> or <ios></ios>• Attributes: android:<attribute> or ios:<attribute>
• Ex: <label android:class="…" ios:class="…" />
Write once by default.Target specific platform capabilities when needed.
{demo}
Handling EventsXML<button text="Click Me" tap="{{ onTap }}" ...
JS (ViewModel)function pageViewModel() {
var viewModel;viewModel.onTap = function() {
alert("You tapped me!");} return viewModel;
}
exports.pageViewModel = pageViewModel;
JS (View)function onViewLoad(args) {
var page = args.object; page.bindingContext = pageViewModel();
}
• Create event handlers in JavaScript
• Bind to event names
Handling Eventstaplabel.on(gestures.GestureTypes.tap, function (args) {
console.log("Tap");});
swipelabel.on(gestures.GestureTypes.swipe, function (args) {
console.log("Swipe Direction: " + args.direction); });
Multiple eventslabel.on("tap, doubleTap, longPress", function (args) {
console.log("Event: " + args.eventName);});
• Tap• Double Tap• Long Press• Swipe• Pan• Pinch• Rotation• Touch
{demo}
Debugging
“If debugging is the process of removing software bugs, then programming must be the process of putting them in.”
- Edsger Dijkstra
Debugging Strategies• Debug by alert (no really)• Debug by console.log• Debug by Developer Tools• Debug by IDE
• Visual Studio• Visual Studio Code
Debug By Alert
{demo}
Telerik UI for NativeScript
- Open source- Widgets: ListView,
SlideDrawer- No support
UI for {N}
- Widgets: Chart, Calendar, DataForm
- No support in entry pricing
- UI for {N} can buy this version for support
UI for {N} PROFREE $199/$599 (with support)
Advanced, rich, native UI widgets for iOS and Android
Telerik UI for NativeScript
npm install nativescript-telerik-ui --save
• Add powerful ListView, SlideDrawer to apps
• Free native widgets
• Support available with PRO license
Custom XML Components<page xmlns:custom="modules/mymodule">
<custom:MyCustomControl /></page>
• Encapsulate reusable UI in components• JS only, OR• XML + CSS + JS
• Add to pages with xmlns
modulesmymodule
.XML
MyCustomControl.js
MyCustomControl.css
MyCustomControl.xml
{demo}
Navigating Views
Basics
• Topmost frame is root-level container
• Facilitates navigation between views
"topmost frame"
var frameModule = require("ui/frame");var topmost = frameModule.topmost();
Navigating with "topmost"1. By File Nametopmost.navigate("details-page");
2. With Navigation Entryvar navigationEntry = {
moduleName: "details-page",context: {info: "something"},animated: false
};topmost.navigate(navigationEntry);
3. Dynamically with Functionvar factoryFunc = function () {
var page = new pagesModule.Page();page.content = ...return page;
};topmost.navigate(factoryFunc);
• Always navigating with topmost.navigate()
• Pass context to views and parse in onNavigatedTo event
• Go back with:• topmost.goBack();
View transitionsvar navigationEntry = {
moduleName: "main-page",animated: true,transition: {
name: "slide",duration: 380,curve: "easeIn" }
};topmost.navigate(navigationEntry);
• curl (same as curlUp) (iOS only)• curlUp (iOS only)• curlDown (iOS only)• explode (Android Lollipop and later)• fade• flip (same as flipRight)• flipRight• flipLeft• slide (same as slideLeft)• slideLeft• slideRight• slideTop• slideBottom
Different transitions can be set for iOS and Android
{demo}
Basic Data Binding
Data binding
{{ newTodo }}
{demo}
Data binding improved
Data binding lists<Page>
<StackLayout><ListView items="{{ items }}" height="200">
<ListView.itemTemplate><Label text="{{ $value }}" />
</ListView.itemTemplate></ListView>
</StackLayout></Page>
• Bind to array or collection of data
• Access named properties or $value
• Access parent binding context with $parents• EX: OrderID in list of Order Details
{{ todos }}
{{ $value }}
{demo}
Data binding expressions
Static Expression<TextField text="{{ sourceProperty, sourceProperty + ' some static text' }}" />
Ternary Operator<TextField class="{{ isConditionTrue ? 'myClass true' : 'myClass false' }}" />
Converter<TextField text="{{ testDate, testDate | dateConverter('DD.MM.YYYY') }}" />
Execute expressions during data binding to determine visual state
Source Property Binding Expression
Convertersvar dateConverter = {
toView: function (value, format) {var result = format;var day = value.getDate();...//Return formatted model valuereturn result;},toModel: function (value, format) {
//Convert value from UI format to model formatreturn result;
}}
• Encapsulate more complex data binding formatting rules
• Can be one-way or two-way
• Add to page binding context OR global application context
Data binding expressionsFeature Example
property access obj1.obj2.prop1
array access arrayVar[indexVar]
logical operators !var1
unary operators +var1, -var2
binary operators var1 + var2
comparison operators var1 > var2
logical comparison operators var1>1 && var2>1.
ternary operator var1 ? var2 : var3
grouping parenthesis (a + b) * (c + d)
function calls myFunc(var1, var2, ..., varN)
filters expression \| filter1(param1, ...) | filter 2
{{ total, total +' items left' }}
{demo}
Basic Styling with CSS
CSS
Convention:
app.css <-- Global styles
[viewName].css <-- View styles
[viewName].[platform].css
Supported Properties• color• background-color• background-image• background-repeat• background-position• background-size• border-color• border-width• border-radius• font• font-family• font-size
• font-style• font-weight• text-align• text-decoration• text-transform• vertical-align• horizontal-align• margin• margin-top• margin-right• margin-bottom• margin-left
• width• height• min-width• min-height• padding• padding-top• padding-right• padding-bottom• padding-left• visibility• opacity
Supported Selectors
• Type• button { color: red; }
• Class• .mybutton { color: green; }
• ID• #myButton { color: #FFF; }
{demo}
Custom Fonts1. Use TTF or OTF fonts2. Put fonts in: app > fonts3. Use in CSS
.icon { font-size: 30; font-family: 'FontAwesome';
}
{demo}
Sass & LESS• Use Sass or LESS syntax• Auto-compiled
$ tns install sassOR
$tns install less
Pre-lunch Wrap-up
Bottom line• Access all native APIs with JavaScript• 0-day support for new APIs• Use modules to increase cross-platform “write
once”• Use CSS to style native UI• Use XML markup to define views• Use CLI (+ IDE integrations) or Telerik Platform to
build and debug
Lunch Break Resume @ 1PM
Workshop Agenda
• Intro to NativeScript• NativeScript core concepts• “Hello World”• Defining Views• Debugging JavaScript• Basic data binding• Styling views with CSS
• Intro to Angular 2 concepts• Angular 2 + NativeScript• Navigating views• BONUS
• Extending with plugins• Adding animations• Using Telerik Platform
Ante Meridiem (9AM to Noon) Post Meridiem (1PM to 4PM)
Adoption trendsWarm the brains-up after lunch
Adoption Goals (2016)Goal for 2016: Grow NativeScript adoption by 15x
Jan Feb Mar Apr May Jun Jul Aug Sept Oct Nov DecAug Sept Oct Nov Dec
2x
2016
5x
3x
Google Angular2 event (“ngConf”);NativeScript Angular2 push begins
Measured* active developers(via NativeScript CLI)
• Active monthly CLI users doubledAug to Dec ‘15
• Doubled again Dec to Feb ‘16
• On track to double again by end of April
60% increase in new users since January
Developer Comments
Join the growing NativeScript
community on Slack
bit.ly/nativescript-slack
Integrations & Ecosystem
Plugin Ecosystem
Plugin Ecosystem
Reusable libraries IDEs Verified Plugins
Modulus Sachse Construction Day Care This or That!
PocketSmith
“With NativeScript it became apparent quickly that we would no longer have a need for iOS and Android specialists—our Microsoft .NET team became fully functional—fast.”
Allan Kreyer, CIM Mobility Founder
Angular 2 & NativeScript
One framework. Mobile & desktop.
Mobile
ResponsivePWA (Progressive Web Apps)Native Mobile
Why Angular 2?
Template< ... >
Component{ ... }
Metadata
Directive{ ... }
InjectorService A
Service B
RendererTemplate
< ... >
RendererTemplate
< ... >
An Intro to Angular 2
Template< ... >
Component{ ... }
Metadata
Directive{ ... }
InjectorService A
Service B
Template< ... >
Component{ ... }
Metadata
<!DOCTYPE html><html>
<head><base href="/">
</head>
<body ng-app=”app">
<app>Loading...</app>
<script src="bundle.js"></script>
</body>
</html>
index.html
const AppComponent = {template: `<h1>Root Component</h1>
`};
angular.module('app', []).component('app', AppCompon3ent);
app.js
Root Component
const AppComponent = {template: `<h1>Root Component</h1>
`};
angular.module('app', []).component('app', AppComponent);
app.js
const AppComponent = {template: `<h1>Root Component</h1>
`};
angular.module('app', []).component('app', AppComponent);
app.component.ts
import { Component } from ”@angular/core”
const AppComponent = {template: `<h1>Root Component</h1>
`};
angular.module('app', []).component('app', AppComponent);
app.component.ts
import { Component } from ”@angular/core”
@Component({template: `<h1>Root Component</h1>
`});
angular.module('app', []).component('app', AppComponent);
app.component.ts
import { Component } from ”@angular/core”
@Component({selector: 'app',template: `<h1>Root Component</h1>
`});
angular.module('app', []).component('app', AppComponent);
app.component.ts
<!DOCTYPE html><html>
<head><base href="/">
</head>
<body ng-app=”app">
<app>Loading...</app>
<script src="bundle.js"></script>
</body>
</html>
index.html
<!DOCTYPE html><html>
<head><base href="/">
</head>
<body>
<app>Loading...</app>
<script src="bundle.js"></script>
</body>
</html>
index.html
import { Component } from ”@angular/core”
@Component({selector: 'app',template: `<h1>Root Component</h1>
`});
angular.module('app', []).component('app', AppComponent);
app.component.ts
import { Component } from ”@angular/core”
@Component({selector: 'app',template: `<h1>Root Component</h1>
`});
export class AppComponent {}
app.component.ts
Root Component
import { Component } from ”@angular/core”
@Component({selector: 'app',template: `<h1>Root Component</h1>
`});
export class AppComponent {}
app.component.ts
import { Component } from ”@angular/core”
@Component({selector: 'app',template: `<h1>Root Component</h1>
`});
export class AppComponent {message: 'Root Component'
}
app.component.ts
import { Component } from ”@angular/core”
@Component({selector: 'app',template: `<h1>{{ message }}</h1>
`});
export class AppComponent {message: 'Root Component'
}
app.component.ts
Root Component
import { Component } from ”@angular/core”
@Component({selector: 'app',template: `<h1>{{ message }}</h1>
`});
export class AppComponent {message: 'Root Component'
}
app.component.ts
import { Component } from ”@angular/core”
@Component({selector: 'app',template: `<input value=”{{ message }}”>
`});
export class AppComponent {message: 'Root Component'
}
app.component.ts
import { Component } from ”@angular/core”
@Component({selector: 'app',template: `<input [value]=”message”>
`});
export class AppComponent {message: 'Root Component'
}
app.component.ts
[ value ] or {{ value }} = One way binding from class to view
import { Component } from ”@angular/core”
@Component({selector: 'app',template: `<input [value]=”message”>
`});
export class AppComponent {message: 'Root Component'
}
app.component.ts
import { Component } from ”@angular/core”
@Component({selector: 'app',template: `<input [value]=”message”><button (click)=“showMessage()”>Show Message</button>
`});
export class AppComponent {message: 'Root Component’;showMessage() {
alert(this.message); }
}
app.component.ts
Root Component Show Me
The page at http://localhost/3000 says:
Root Component
( event ) = Binds an event to a function
import { Component } from ”@angular/core”
@Component({selector: 'app',template: `<input [value]=”message”><button (click)=“showMessage()”>Show Message</button>
`});
export class AppComponent {message: 'Root Component’;showMessage() {
alert(this.message); }
}
app.component.ts
import { Component } from ”@angular/core”
@Component({selector: 'app',template: `<input [(ngModel)]=”message”><button (click)=“showMessage()”>Show Message</button>
`});
export class AppComponent {message: 'Root Component’;showMessage() {
alert(this.message); }
}
app.component.ts
[(ngModel)] = Two way binding
Services And Injection
export class MessageService {message: string = ”Service Message”
}
message.service.ts
import { Injectable } from ”@angular/core”
export class MessageService {message: string = ”Service Message”
}
message.service.ts
import { Injectable } from ”@angular/core”
@Injectable()export class MessageService {
message: string = ”Service Message”}
message.service.ts
import { Component } from ”@angular/core”
@Component({selector: 'app',template: `<input [(ngModel)]=”message”><button (click)=“showMessage()”>Show Message</button>
`});
export class AppComponent {message: 'Root Component’;showMessage() {
alert(this.message); }
} app.component.ts
import { Component } from ”@angular/core”import { MessageService } from ”./message.service”
@Component({selector: 'app',template: `<input [(ngModel)]=”message”><button (click)=“showMessage()”>Show Message</button>
`});
export class AppComponent {message: 'Root Component’;showMessage() {
alert(this.message); }
} app.component.ts
@Component({selector: 'app',providers: [MessageService]template: `<input [(ngModel)]=”message”><button (click)=“showMessage()”>Show Message</button>
`});
export class AppComponent {message: string;showMessage() {
alert(this.message); }constructor(MessageService _messageService) {this.message = _messageService.message;
} app.component.ts
Service Message Show Me
The page at http://localhost/3000 says:
Service Message
Directives
import { Component } from ”@angular/core”import { MessageService } from ”./message.service.ts”
@Component({selector: 'app',providers: [MessageService]template: `<input [(ngModel)]=”message”><button (click)=“showMessage()”>Show Message</button>
`});
export class AppComponent {message: string;showMessage() {
alert(this.message); }constructor(MessageService _messageService) {this.message = _messageService.message;
}} app.component.ts
import { MessageService } from ”./message.service.ts”
export class MessageDirective {}
message.directive.ts
import { MessageService } from ”./message.service.ts”
@Component({selector: ’message',providers: [MessageService]template: `<input [(ngModel)]=”message”><button (click)=“showMessage()”>Show Message</button>
`});
export class MessageDirective {}
message.directive.ts
import { MessageService } from ”./message.service.ts”
@Component({selector: ’message',providers: [MessageService]template: `<input [(ngModel)]=”message”><button (click)=“showMessage()”>Show Message</button>
`});
export class MessageDirective {message: string;showMessage() {
alert(this.message); }constructor(MessageService _messageService) {this.message = _messageService.message;
} }
message.directive.ts
import { Component } from ”@angular/core”import { MessageService } from ”./message.service.ts”
@Component({selector: 'app',providers: [MessageService]template: `<input [(ngModel)]=”message”><button (click)=“showMessage()”>Show Message</button>
`});
export class AppComponent {message: string;showMessage() {
alert(this.message); }constructor(MessageService _messageService) {this.message = _messageService.message;
}} app.component.ts
import { Component } from ”@angular/core”import { MessageDirective } from ”./message.directive.ts”
@Component({selector: 'app',providers: [MessageService]template: `<input [(ngModel)]=”message”><button (click)=“showMessage()”>Show Message</button>
`});
export class AppComponent {message: string;showMessage() {
alert(this.message); }constructor(MessageService _messageService) {this.message = _messageService.message;
}} app.component.ts
import { Component } from ”@angular/core”import { MessageDirective } from ”./message.directive.ts”
@Component({selector: 'app',directives: [MessageDirective]template: `<input [(ngModel)]=”message”><button (click)=“showMessage()”>Show Message</button>
`});
export class AppComponent {message: string;showMessage() {
alert(this.message); }constructor(MessageService _messageService) {this.message = _messageService.message;
}} app.component.ts
import { Component } from ”@angular/core”import { MessageDirective } from ”./message.directive.ts”
@Component({selector: 'app',directives: [MessageDirective]template: `<message></message>
`});
export class AppComponent {message: string;showMessage() {
alert(this.message); }constructor(MessageService _messageService) {this.message = _messageService.message;
}}
app.component.ts
import { Component } from ”@angular/core”import { MessageDirective } from ”./message.directive.ts”
@Component({selector: 'app',directives: [MessageDirective]template: `<message></message>
`});
export class AppComponent {}
app.component.ts
Service Message Show Me
The page at http://localhost/3000 says:
Service Message
{demo}Let’s Code
an open source framework for building truly native mobile apps with JavaScript. Use web skills, like Angular and CSS, and get native UI and performance on iOS and Android.
NativeScript is…
NativeScriptdelivers the promises
of “hybrid.”
APENDIX
Adding TypeScript
tns install typescript
{demo}
Common App Patterns• Services
• An object that is responsible for getting and setting data
• Models• Super dumb objects that define the structure of the data
• ViewModels• AKA Controllers. Controls the state of the UI and performs when changes are made to model objects.
Angular 2
Data binding with Angular• {{ }} – still works!
• You can still use {N}'s standard binding…• But you can do it even better.
• [] – Property binding • One way.• Like array notation in JavaScript. One way
• () – Event Binding• When you want to bind to an event.
• Two Way – [(ngModel)]• Almost always used with ngModel
Extra Angular Goodies• Dependency Injection• Routing• Components• Pipes• Services• FAST
Using Telerik PlatformCloud-based tooling for NativeScript
Why?• Cloud based, zero setup• Build for iOS from Windows• Deploy to device without provisioning profiles• Manage app properties faster
AppBuilder
Screen Builder
Companion App
{demo}
Animations
Animation basics
Animate:• opacity• backgroundColor• translateX and translateY• scaleX and scaleY• rotate
Configure:• target (UI element)• duration (in ms)• delay• iterations• curve
Simple animationvar view = page.getViewById("myLabel");
view.animate({translate: { x: 0, y: 100},duration: 1000,curve: enums.AnimationCurve.easeIn
});
• Animations can be chained together
• Multiple properties and elements can be animated
• Return a promise that can be canceled
{demo}