Add animations demo to the gallery app, make vertical alignment center and visibility collapsed backward compatible

This commit is contained in:
Panayot Cankov
2017-01-25 13:17:33 +02:00
parent ba2d5d42e6
commit 0dd8f985c4
12 changed files with 376 additions and 11 deletions

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 311 B

View File

@@ -0,0 +1,175 @@
import * as observable from "data/observable";
import * as pages from "ui/page";
import * as buttonModule from "ui/button";
import * as abs from "ui/layouts/absolute-layout";
import * as animationModule from "ui/animation";
import * as colorModule from "color";
import * as model from "./model";
import * as enums from "ui/enums";
import * as frame from "ui/frame";
import * as trace from "trace";
var vm = new model.ViewModel();
var page: pages.Page;
var panel: abs.AbsoluteLayout;
var button1: buttonModule.Button;
var button2: buttonModule.Button;
var button3: buttonModule.Button;
var buttonAnimation: animationModule.Animation;
var panelAnimation: animationModule.Animation;
export function pageLoaded(args: observable.EventData) {
page = <pages.Page>args.object;
page.bindingContext = vm;
panel = page.getViewById<abs.AbsoluteLayout>("panel1");
button1 = page.getViewById<buttonModule.Button>("button1");
button2 = page.getViewById<buttonModule.Button>("button2");
button3 = page.getViewById<buttonModule.Button>("button3");
trace.enable();
trace.addCategories(trace.categories.concat(trace.categories.Animation));
}
export function onSlideOut(args: observable.EventData) {
console.log("onSlideOut");
var curve = enums.AnimationCurve.easeOut;
var buttonAnimations = [
{ target: button1, translate: { x: -240, y: 0 }, scale: { x: 0.5, y: 0.5 }, opacity: 0, duration: vm.duration, delay: 0, iterations: vm.iterations, curve: curve },
{ target: button2, translate: { x: -240, y: 0 }, scale: { x: 0.5, y: 0.5 }, opacity: 0, duration: vm.duration, delay: vm.duration, iterations: vm.iterations, curve: curve },
{ target: button3, translate: { x: -240, y: 0 }, scale: { x: 0.5, y: 0.5 }, opacity: 0, duration: vm.duration, delay: vm.duration * 2, iterations: vm.iterations, curve: curve },
]
buttonAnimation = new animationModule.Animation(buttonAnimations, vm.playSequentially);
panelAnimation = panel.createAnimation({ opacity: 0, scale: { x: 0.5, y: 0.5 }, rotate: -360, backgroundColor: new colorModule.Color("red"), duration: vm.duration, iterations: vm.iterations, curve: enums.AnimationCurve.easeInOut });
buttonAnimation.play()
.then(() => panelAnimation.play())
.catch((e) => console.log(e.message));
}
export function onSlideIn(args: observable.EventData) {
console.log("onSlideIn");
var curve = enums.AnimationCurve.easeIn;
panelAnimation = panel.createAnimation({ opacity: 1, scale: { x: 1, y: 1 }, rotate: 0, backgroundColor: new colorModule.Color("yellow"), duration: vm.duration, iterations: vm.iterations, curve: enums.AnimationCurve.easeInOut });
var buttonAnimations = [
{ target: button3, translate: { x: 0, y: 0 }, scale: { x: 1, y: 1 }, opacity: 1, duration: vm.duration, delay: 0, iterations: vm.iterations, curve: curve },
{ target: button2, translate: { x: 0, y: 0 }, scale: { x: 1, y: 1 }, opacity: 1, duration: vm.duration, delay: vm.duration, iterations: vm.iterations, curve: curve },
{ target: button1, translate: { x: 0, y: 0 }, scale: { x: 1, y: 1 }, opacity: 1, duration: vm.duration, delay: vm.duration * 2, iterations: vm.iterations, curve: curve },
]
buttonAnimation = new animationModule.Animation(buttonAnimations, vm.playSequentially);
panelAnimation.play()
.then(() => buttonAnimation.play())
.catch((e) => console.log(e.message));
}
export function onCancel(args: observable.EventData) {
console.log("onCancel");
if (panelAnimation && panelAnimation.isPlaying) {
panelAnimation.cancel();
}
if (buttonAnimation && buttonAnimation.isPlaying) {
buttonAnimation.cancel();
}
}
export function onTap(args: observable.EventData) {
console.log((<any>args.object).text);
}
export function onSingle(args: observable.EventData) {
console.log("onSingle");
button1.animate({
opacity: 0.75,
backgroundColor: new colorModule.Color("Red"),
translate: { x: 100, y: 100 },
scale: { x: 2, y: 2 },
rotate: 180,
duration: vm.duration,
delay: 0,
iterations: vm.iterations,
curve: enums.AnimationCurve.linear,
})
.then(() => console.log("Animation finished"))
.catch((e) => console.log(e.message));
}
export function onSequence(args: observable.EventData) {
console.log("onSequence");
button3.animate({
translate: { x: 80, y: -40 },
scale: { x: 0.9, y: 0.3 },
rotate: 25,
duration: 1000
})
.then(() => button3.animate({
translate: { x: 0, y: -80 },
scale: { x: 0.5, y: 0.5 },
rotate: -25,
duration: 1000
}))
.then(() => button3.animate({
translate: { x: -80, y: -40 },
scale: { x: 0.5, y: 0.9 },
rotate: 45,
duration: 1000
}))
.then(() => button3.animate({
translate: { x: 0, y: 0 },
scale: { x: 1, y: 1 },
rotate: 0,
duration: 1000
}))
.then(() => console.log("Animation finished"))
.catch((e) => console.log(e.message));
}
export function onInterrupted(args: observable.EventData) {
console.log("onInterrupt");
setTimeout(() => {
button3.animate({
translate: { x: 80, y: -40 },
scale: { x: 0.9, y: 0.3 },
rotate: 25,
duration: 1000
});
}, 700 * 0);
setTimeout(function() {
button3.animate({
translate: { x: 0, y: -80 },
scale: { x: 0.5, y: 0.5 },
rotate: -25,
duration: 1000
})
}, 700 * 1);
setTimeout(function() {
button3.animate({
translate: { x: -80, y: -40 },
scale: { x: 0.5, y: 0.9 },
rotate: 45,
duration: 1000
})
}, 700 * 2);
setTimeout(function() {
button3.animate({
translate: { x: 0, y: 0 },
scale: { x: 1, y: 1 },
rotate: 0,
duration: 1000
})
}, 700 * 3);
}
export function onOpacity(args: observable.EventData) {
frame.topmost().navigate("./opacity");
}

View File

@@ -0,0 +1,36 @@
<Page xmlns="http://schemas.nativescript.org/tns.xsd" loaded="pageLoaded" id="mainPage">
<StackLayout orientation="vertical">
<StackLayout orientation="vertical" backgroundColor="LightGray" paddingTop="5" paddingBottom="5">
<Label text="{{ duration, 'Duration: ' + duration + ' ms' }}" width="180" />
<Slider minValue="0" maxValue="10000" value="{{ duration }}" margin="0 15" />
<Label text="{{ iterations, 'Iterations: ' + iterations + ' times' }}" width="180" />
<Slider minValue="0" maxValue="10" value="{{ iterations }}" margin="0 15" />
<StackLayout orientation="horizontal" horizontalAlignment="center">
<Label text="Play Sequentially?"/>
<Switch marginLeft="10" checked="{{ playSequentially }}"/>
</StackLayout>
<StackLayout orientation="horizontal" marginTop="5" marginBottom="5" horizontalAlignment="center" paddingLeft="5" paddingRight="5">
<Button text="Out" tap="onSlideOut" width="40" marginLeft="5" marginRight="5" />
<Button text="In" tap="onSlideIn" width="40" marginLeft="5" marginRight="5" />
<Button text="Single" tap="onSingle" width="70" marginLeft="5" marginRight="5" />
<Button text="Cancel" tap="onCancel" width="70" marginLeft="5" marginRight="5" />
<Button text="Opacity" tap="onOpacity" width="70" marginLeft="5" marginRight="5" />
</StackLayout>
<StackLayout orientation="horizontal" marginTop="5" marginBottom="5" horizontalAlignment="center" paddingLeft="5" paddingRight="5">>
<Button text="Sequence" width="80" marginLeft="5" marginRight="5" tap="onSequence" />
<Button text="Interrupted" width="80" marginLeft="5" marginRight="5" tap="onInterrupted" />
</StackLayout>
</StackLayout>
<AbsoluteLayout id="panel1" backgroundColor="Yellow" width="300" height="190" clipToBounds="true" marginTop="10">
<Button id="button1" text="Button 1" backgroundColor="White" width="180" height="50" left="60" top="10" tap="onTap" borderWidth="1" borderColor="red" />
<Button id="button2" text="Button 2" backgroundColor="White" width="180" height="50" left="60" top="70" tap="onTap" borderWidth="1" borderColor="red" />
<Button id="button3" text="Button 3" backgroundColor="White" width="180" height="50" left="60" top="130" tap="onTap" borderWidth="1" borderColor="red" />
</AbsoluteLayout>
</StackLayout>
</Page>

View File

@@ -0,0 +1,37 @@
import observable = require("data/observable");
export class ViewModel extends observable.Observable {
constructor() {
super();
this._duration = 3000;
this._iterations = 1;
}
private _playSequentially: boolean;
get playSequentially(): boolean {
return this._playSequentially;
}
set playSequentially(value: boolean) {
this._playSequentially = value;
this.notify({ object: this, eventName: observable.Observable.propertyChangeEvent, propertyName: "playSequentially", value: value });
}
private _duration: number;
get duration(): number {
return this._duration;
}
set duration(value: number) {
this._duration = value;
this.notify({ object: this, eventName: observable.Observable.propertyChangeEvent, propertyName: "duration", value: value });
}
private _iterations: number;
get iterations(): number {
return this._iterations;
}
set iterations(value: number) {
this._iterations = value;
this.notify({ object: this, eventName: observable.Observable.propertyChangeEvent, propertyName: "iterations", value: value });
}
}

View File

@@ -0,0 +1,27 @@
.complex {
width: 45;
height: 45;
margin: 1;
background-image: url('~/gallery-app/animations/bkg.png');
background-repeat:repeat-x;
background-position: 20% 80%;
background-color: lightyellow;
background-size: 25% 50%;
border-radius: 20;
border-width: 4;
border-color: red;
}
.simple {
width: 45;
height: 45;
margin: 1;
border-radius: 20;
background-color: lightgreen;
}
.none {
width: 45;
height: 45;
margin: 1;
}

View File

@@ -0,0 +1,47 @@
import observable = require("data/observable");
import pages = require("ui/page");
import view = require("ui/core/view");
import animationModule = require("ui/animation");
import slider = require("ui/slider");
import wrapLayout = require("ui/layouts/wrap-layout");
var page: pages.Page;
var opacitySlider: slider.Slider;
var container: wrapLayout.WrapLayout;
export function pageLoaded(args: observable.EventData) {
page = <pages.Page>args.object;
opacitySlider = page.getViewById<slider.Slider>("opacitySlider");
container = page.getViewById<wrapLayout.WrapLayout>("container");
}
export function onSetOpacity(args: observable.EventData) {
var newOpacity = opacitySlider.value / 100;
container.eachChildView((view: view.View) => {
view.opacity = newOpacity;
return true;
});
}
var animationSet: animationModule.Animation;
export function onAnimateOpacity(args: observable.EventData) {
var newOpacity = opacitySlider.value / 100;
var animationDefinitions = new Array<animationModule.AnimationDefinition>();
container.eachChildView((view: view.View) => {
animationDefinitions.push({
target: view,
opacity: newOpacity,
duration: 5000
});
return true;
});
animationSet = new animationModule.Animation(animationDefinitions);
animationSet.play();
}
export function onReset(args: observable.EventData) {
if (animationSet.isPlaying) {
animationSet.cancel();
}
}

View File

@@ -0,0 +1,35 @@
<Page xmlns="http://schemas.nativescript.org/tns.xsd" loaded="pageLoaded" id="opacityPage">
<StackLayout orientation="vertical">
<StackLayout orientation="vertical">
<Label text="opacity" width="180" />
<Slider id="opacitySlider" minValue="0" maxValue="100" width="180" />
<Button text="Set" tap="onSetOpacity"/>
<Button text="Animate" tap="onAnimateOpacity"/>
<Button text="Reset" tap="onReset"/>
</StackLayout>
<WrapLayout orientation="horizontal" id="container">
<StackLayout class="complex"/>
<Button text="Button" class="complex"/>
<Label text="Label" class="complex"/>
<Image src="~/test-icon.png" class="complex"/>
<TextField text="TextField" class="complex"/>
<TextView text="TextView" class="complex"/>
<StackLayout class="simple"/>
<Button text="Button" class="simple"/>
<Label text="Label" class="simple"/>
<Image src="~/test-icon.png" class="simple"/>
<TextField text="TextField" class="simple"/>
<TextView text="TextView" class="simple"/>
<StackLayout class="none"/>
<Button text="Button" class="none"/>
<Label text="Label" class="none"/>
<Image src="~/test-icon.png" class="none"/>
<TextField text="TextField" class="none"/>
<TextView text="TextView" class="none"/>
</WrapLayout>
</StackLayout>
</Page>

View File

@@ -0,0 +1,2 @@
{ "name" : "animations",
"main" : "app.js" }

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -40,6 +40,12 @@
<Button tag="views/list-picker" text="ListPicker" tap="itemTap" /> <Button tag="views/list-picker" text="ListPicker" tap="itemTap" />
<Button tag="views/segmented-bar" text="SegmentedBar" tap="itemTap" /> <Button tag="views/segmented-bar" text="SegmentedBar" tap="itemTap" />
</StackLayout> </StackLayout>
<Label class="title" text="Animations" />
<StackLayout>
<Button tag="animations/configurable" text="configurable" tap="itemTap" />
<Button tag="animations/opacity" text="opacity" tap="itemTap" />
</StackLayout>
</StackLayout> </StackLayout>
</ScrollView> </ScrollView>
</Page> </Page>

View File

@@ -65,6 +65,13 @@ declare module "data/observable" {
* Observable is used when you want to be notified when a change occurs. Use on/off methods to add/remove listener. * Observable is used when you want to be notified when a change occurs. Use on/off methods to add/remove listener.
*/ */
class Observable { class Observable {
/**
* Please note that should you be using the `new Observable({})` constructor, it is **obsolete** since v3.0,
* and you have to migrate to the "data/observable" `fromObject({})` or the `fromObjectRecursive({})` functions.
*/
constructor();
/** /**
* String value used when hooking to propertyChange event. * String value used when hooking to propertyChange event.
*/ */

View File

@@ -1250,16 +1250,8 @@ export namespace VerticalAlignment {
export const BOTTOM: "bottom" = "bottom"; export const BOTTOM: "bottom" = "bottom";
export const STRETCH: "stretch" = "stretch"; export const STRETCH: "stretch" = "stretch";
export const isValid = makeValidator<VerticalAlignment>(TOP, MIDDLE, BOTTOM, STRETCH); export const isValid = makeValidator<VerticalAlignment>(TOP, MIDDLE, BOTTOM, STRETCH);
export const parse = value => { export const parse = (value: string) => value.toLowerCase() === "center" ? MIDDLE : parseStrict(value);
const lower = value && value.toLowerCase(); const parseStrict = makeParser<VerticalAlignment>(isValid);
if (lower === "canter") {
return MIDDLE;
} else if (isValid(lower)) {
return lower;
} else {
throw new Error("Invalid value: " + value);
}
}
} }
export const verticalAlignmentProperty = new CssProperty<Style, VerticalAlignment>({ name: "verticalAlignment", cssName: "vertical-align", defaultValue: VerticalAlignment.STRETCH, affectsLayout: isIOS, valueConverter: VerticalAlignment.parse }); export const verticalAlignmentProperty = new CssProperty<Style, VerticalAlignment>({ name: "verticalAlignment", cssName: "vertical-align", defaultValue: VerticalAlignment.STRETCH, affectsLayout: isIOS, valueConverter: VerticalAlignment.parse });
@@ -2025,7 +2017,8 @@ export namespace Visibility {
export const HIDDEN: "hidden" = "hidden"; export const HIDDEN: "hidden" = "hidden";
export const COLLAPSE: "collapse" = "collapse"; export const COLLAPSE: "collapse" = "collapse";
export const isValid = makeValidator<Visibility>(VISIBLE, HIDDEN, COLLAPSE); export const isValid = makeValidator<Visibility>(VISIBLE, HIDDEN, COLLAPSE);
export const parse = makeParser<Visibility>(isValid); export const parse = (value: string) => value.toLowerCase() === "collapsed" ? COLLAPSE : parseStrict(value);
const parseStrict = makeParser<Visibility>(isValid);
} }
export const visibilityProperty = new CssProperty<Style, Visibility>({ export const visibilityProperty = new CssProperty<Style, Visibility>({