mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-15 19:26:42 +08:00
feat: touch animations demo in toolbox
This commit is contained in:
@ -14,6 +14,7 @@
|
|||||||
<Button text="visibility-vs-hidden" tap="{{ viewDemo }}" class="btn btn-primary btn-view-demo" />
|
<Button text="visibility-vs-hidden" tap="{{ viewDemo }}" class="btn btn-primary btn-view-demo" />
|
||||||
<Button text="image-async" tap="{{ viewDemo }}" class="btn btn-primary btn-view-demo" />
|
<Button text="image-async" tap="{{ viewDemo }}" class="btn btn-primary btn-view-demo" />
|
||||||
<Button text="vector-image" tap="{{ viewDemo }}" class="btn btn-primary btn-view-demo" />
|
<Button text="vector-image" tap="{{ viewDemo }}" class="btn btn-primary btn-view-demo" />
|
||||||
|
<Button text="touch-animations" tap="{{ viewDemo }}" class="btn btn-primary btn-view-demo" />
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
|
314
apps/toolbox/src/pages/touch-animations.ts
Normal file
314
apps/toolbox/src/pages/touch-animations.ts
Normal file
@ -0,0 +1,314 @@
|
|||||||
|
import { Observable, EventData, Page, CoreTypes, TouchManager, TouchAnimationOptions, Color, View } from '@nativescript/core';
|
||||||
|
|
||||||
|
let page: Page;
|
||||||
|
|
||||||
|
export function navigatingTo(args: EventData) {
|
||||||
|
page = <Page>args.object;
|
||||||
|
page.bindingContext = new TouchAnimationsModel(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TouchAnimationsModel extends Observable {
|
||||||
|
touchAnimation: TouchAnimationOptions = {
|
||||||
|
down: {
|
||||||
|
scale: { x: 0.95, y: 0.95 },
|
||||||
|
backgroundColor: new Color('purple'),
|
||||||
|
duration: 250,
|
||||||
|
curve: CoreTypes.AnimationCurve.easeInOut,
|
||||||
|
},
|
||||||
|
up: {
|
||||||
|
scale: { x: 1, y: 1 },
|
||||||
|
backgroundColor: new Color('#30bcff'),
|
||||||
|
duration: 250,
|
||||||
|
curve: CoreTypes.AnimationCurve.easeInOut,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
touchAnimationLabel: TouchAnimationOptions = {
|
||||||
|
down: {
|
||||||
|
scale: { x: 0.85, y: 0.85 },
|
||||||
|
duration: 150,
|
||||||
|
curve: CoreTypes.AnimationCurve.easeInOut,
|
||||||
|
},
|
||||||
|
up: {
|
||||||
|
scale: { x: 1, y: 1 },
|
||||||
|
duration: 150,
|
||||||
|
curve: CoreTypes.AnimationCurve.easeInOut,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
touchAnimationLayout: TouchAnimationOptions = {
|
||||||
|
down: {
|
||||||
|
scale: { x: 0.85, y: 0.85 },
|
||||||
|
opacity: 0.7,
|
||||||
|
duration: 250,
|
||||||
|
curve: CoreTypes.AnimationCurve.easeInOut,
|
||||||
|
},
|
||||||
|
up: {
|
||||||
|
scale: { x: 1, y: 1 },
|
||||||
|
opacity: 1,
|
||||||
|
duration: 250,
|
||||||
|
curve: CoreTypes.AnimationCurve.easeInOut,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
touchAnimationNative: TouchAnimationOptions = {
|
||||||
|
down: (view: View) => {
|
||||||
|
const shakeIt = () => {
|
||||||
|
// shake when all the way down
|
||||||
|
view
|
||||||
|
.animate({ translate: { x: -20, y: 0 }, scale: { x: 0.95, y: 0.95 }, duration: 60, curve: CoreTypes.AnimationCurve.linear })
|
||||||
|
.then(function () {
|
||||||
|
return view.animate({ translate: { x: 20, y: 0 }, duration: 60, curve: CoreTypes.AnimationCurve.linear });
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
return view.animate({ translate: { x: -20, y: 0 }, duration: 60, curve: CoreTypes.AnimationCurve.linear });
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
return view.animate({ translate: { x: 20, y: 0 }, duration: 60, curve: CoreTypes.AnimationCurve.linear });
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
return view.animate({ translate: { x: -10, y: 0 }, duration: 60, curve: CoreTypes.AnimationCurve.linear });
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
return view.animate({ translate: { x: 10, y: 0 }, duration: 60, curve: CoreTypes.AnimationCurve.linear });
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
return view.animate({ translate: { x: -5, y: 0 }, duration: 60, curve: CoreTypes.AnimationCurve.linear });
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
return view.animate({ translate: { x: 5, y: 0 }, duration: 60, curve: CoreTypes.AnimationCurve.linear });
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
return view.animate({ translate: { x: 0, y: 0 }, duration: 60, curve: CoreTypes.AnimationCurve.linear });
|
||||||
|
})
|
||||||
|
.then(function () {});
|
||||||
|
};
|
||||||
|
if (global.isIOS) {
|
||||||
|
UIView.animateWithDurationDelayUsingSpringWithDampingInitialSpringVelocityOptionsAnimationsCompletion(
|
||||||
|
0.4,
|
||||||
|
0,
|
||||||
|
0.5,
|
||||||
|
3,
|
||||||
|
UIViewAnimationOptions.CurveEaseInOut,
|
||||||
|
() => {
|
||||||
|
view.ios.transform = CGAffineTransformMakeScale(0.95, 0.95);
|
||||||
|
view.opacity = 0.5;
|
||||||
|
view.ios.backgroundColor = new Color('red').ios;
|
||||||
|
view.color = new Color('white');
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
shakeIt();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
view
|
||||||
|
.animate({
|
||||||
|
scale: { x: 0.95, y: 0.95 },
|
||||||
|
opacity: 0.5,
|
||||||
|
backgroundColor: new Color('red'),
|
||||||
|
duration: 400,
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
view.color = new Color('white');
|
||||||
|
shakeIt();
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
up: (view: View) => {
|
||||||
|
if (global.isIOS) {
|
||||||
|
UIView.animateWithDurationDelayUsingSpringWithDampingInitialSpringVelocityOptionsAnimationsCompletion(
|
||||||
|
0.4,
|
||||||
|
0,
|
||||||
|
0.5,
|
||||||
|
3,
|
||||||
|
UIViewAnimationOptions.CurveEaseInOut,
|
||||||
|
() => {
|
||||||
|
view.ios.transform = CGAffineTransformMakeScale(1.2, 1.2);
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
UIView.animateWithDurationDelayUsingSpringWithDampingInitialSpringVelocityOptionsAnimationsCompletion(
|
||||||
|
0.2,
|
||||||
|
0,
|
||||||
|
0.5,
|
||||||
|
3,
|
||||||
|
UIViewAnimationOptions.CurveEaseInOut,
|
||||||
|
() => {
|
||||||
|
view.ios.transform = CGAffineTransformIdentity;
|
||||||
|
view.opacity = 1;
|
||||||
|
view.ios.backgroundColor = new Color('#aee406').ios;
|
||||||
|
view.color = new Color('black');
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
// complete
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
view
|
||||||
|
.animate({
|
||||||
|
scale: { x: 1.2, y: 1.2 },
|
||||||
|
duration: 400,
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
view.color = new Color('black');
|
||||||
|
view
|
||||||
|
.animate({
|
||||||
|
scale: { x: 1, y: 1 },
|
||||||
|
opacity: 1,
|
||||||
|
backgroundColor: new Color('#aee406'),
|
||||||
|
duration: 200,
|
||||||
|
})
|
||||||
|
.then(() => {})
|
||||||
|
.catch(() => {});
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
touchAnimationRotate: TouchAnimationOptions = {
|
||||||
|
down: {
|
||||||
|
scale: { x: 0.85, y: 0.85 },
|
||||||
|
rotate: 6,
|
||||||
|
opacity: 0.7,
|
||||||
|
duration: 250,
|
||||||
|
curve: CoreTypes.AnimationCurve.easeInOut,
|
||||||
|
},
|
||||||
|
up: {
|
||||||
|
scale: { x: 1, y: 1 },
|
||||||
|
rotate: 0,
|
||||||
|
opacity: 1,
|
||||||
|
duration: 250,
|
||||||
|
curve: CoreTypes.AnimationCurve.easeInOut,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
touchAnimationGrow: TouchAnimationOptions = {
|
||||||
|
down: {
|
||||||
|
scale: { x: 1.2, y: 1.2 },
|
||||||
|
backgroundColor: new Color('#325279'),
|
||||||
|
rotate: -4,
|
||||||
|
duration: 250,
|
||||||
|
curve: CoreTypes.AnimationCurve.easeInOut,
|
||||||
|
},
|
||||||
|
up: {
|
||||||
|
scale: { x: 1, y: 1 },
|
||||||
|
backgroundColor: new Color('#006968'),
|
||||||
|
rotate: 0,
|
||||||
|
duration: 900,
|
||||||
|
curve: CoreTypes.AnimationCurve.easeInOut,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
touchAnimationBlowAway: TouchAnimationOptions = {
|
||||||
|
down: (view: View) => {
|
||||||
|
let rotate = 3;
|
||||||
|
const shiftAway = (viewInstance: View, delay = 0) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
viewInstance.animate({ translate: { x: 0, y: -10 }, scale: { x: 1.1, y: 1.1 }, opacity: 0.8, rotate, duration: 200, curve: CoreTypes.AnimationCurve.easeInOut }).catch(function () {});
|
||||||
|
rotate = rotate * -1;
|
||||||
|
}, delay);
|
||||||
|
};
|
||||||
|
let cnt = 0;
|
||||||
|
for (const id of this.elementIds) {
|
||||||
|
shiftAway(this.page.getViewById(id), cnt);
|
||||||
|
cnt += 10;
|
||||||
|
}
|
||||||
|
if (global.isIOS) {
|
||||||
|
UIView.animateWithDurationDelayUsingSpringWithDampingInitialSpringVelocityOptionsAnimationsCompletion(
|
||||||
|
0.4,
|
||||||
|
0,
|
||||||
|
0.5,
|
||||||
|
3,
|
||||||
|
UIViewAnimationOptions.CurveEaseInOut,
|
||||||
|
() => {
|
||||||
|
view.ios.transform = CGAffineTransformMakeScale(0.95, 0.95);
|
||||||
|
view.opacity = 0.5;
|
||||||
|
},
|
||||||
|
() => {}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
view
|
||||||
|
.animate({
|
||||||
|
scale: { x: 0.95, y: 0.95 },
|
||||||
|
opacity: 0.5,
|
||||||
|
duration: 400,
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
up: (view: View) => {
|
||||||
|
const shiftBack = (viewInstance: View, delay = 0) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
viewInstance.animate({ translate: { x: 0, y: 0 }, scale: { x: 1, y: 1 }, opacity: 1, rotate: 0, duration: 200, curve: CoreTypes.AnimationCurve.easeInOut }).catch(function () {});
|
||||||
|
}, delay);
|
||||||
|
};
|
||||||
|
let cnt = 0;
|
||||||
|
for (const id of this.elementIds) {
|
||||||
|
shiftBack(this.page.getViewById(id), cnt);
|
||||||
|
cnt += 10;
|
||||||
|
}
|
||||||
|
if (global.isIOS) {
|
||||||
|
UIView.animateWithDurationDelayUsingSpringWithDampingInitialSpringVelocityOptionsAnimationsCompletion(
|
||||||
|
0.3,
|
||||||
|
0,
|
||||||
|
0.5,
|
||||||
|
3,
|
||||||
|
UIViewAnimationOptions.CurveEaseInOut,
|
||||||
|
() => {
|
||||||
|
view.ios.transform = CGAffineTransformIdentity;
|
||||||
|
},
|
||||||
|
() => {}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
view
|
||||||
|
.animate({
|
||||||
|
scale: { x: 1, y: 1 },
|
||||||
|
opacity: 1,
|
||||||
|
duration: 300,
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
elementIds = ['label', 'buttonTop', 'grid1', 'buttonShake', 'stack1', 'button2', 'button3', 'button4', 'button5'];
|
||||||
|
|
||||||
|
constructor(private page: Page) {
|
||||||
|
super();
|
||||||
|
TouchManager.enableGlobalTapAnimations = true;
|
||||||
|
this.page.on('navigatingFrom', () => {
|
||||||
|
TouchManager.enableGlobalTapAnimations = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
// reuse instance level animations but customize to ensure they are different
|
||||||
|
TouchManager.animations = {
|
||||||
|
down: {
|
||||||
|
...this.touchAnimation.down,
|
||||||
|
backgroundColor: new Color('rgba(48, 188, 255, .7)'),
|
||||||
|
duration: 150,
|
||||||
|
},
|
||||||
|
up: {
|
||||||
|
...this.touchAnimation.up,
|
||||||
|
duration: 150,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
loadedContainer(args) {
|
||||||
|
if (global.isAndroid) {
|
||||||
|
if (args.object.android.setClipToPadding) {
|
||||||
|
args.object.android.setClipToPadding(false);
|
||||||
|
}
|
||||||
|
if (args.object.android.setClipChildren) {
|
||||||
|
args.object.android.setClipChildren(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onTapAnything() {
|
||||||
|
console.log('onTapAnything');
|
||||||
|
}
|
||||||
|
}
|
40
apps/toolbox/src/pages/touch-animations.xml
Normal file
40
apps/toolbox/src/pages/touch-animations.xml
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo" class="page">
|
||||||
|
<Page.actionBar>
|
||||||
|
<ActionBar title="Touch Animations" class="action-bar">
|
||||||
|
</ActionBar>
|
||||||
|
</Page.actionBar>
|
||||||
|
|
||||||
|
<!-- <ScrollView> -->
|
||||||
|
|
||||||
|
<StackLayout class="p-x-20" loaded="{{ loadedContainer }}">
|
||||||
|
<Label id="label" tap="{{ onTapAnything }}" text="Touchable label" class="t-18 c-black text-center m-t-5" touchAnimation="{{ touchAnimationLabel }}" />
|
||||||
|
<Button id="buttonTop" text="Touch me for puple vibes" tap="{{ onTapAnything }}" class="btn btn-primary btn-view-demo" touchAnimation="{{ touchAnimation }}" />
|
||||||
|
<GridLayout id="grid1" rows="auto" columns="*,auto,auto,*" class="p-10 m-y-10" tap="{{ onTapAnything }}" touchAnimation="{{ touchAnimationLayout }}" borderRadius="8" borderWidth="1" borderColor="#999">
|
||||||
|
<ContentView col="1" backgroundColor="gray" borderRadius="15" width="30" height="30" verticalAlignment="middle" />
|
||||||
|
<Label col="2" text="Touchable GridLayout" class="t-18 m-l-10" verticalAlignment="middle" />
|
||||||
|
</GridLayout>
|
||||||
|
|
||||||
|
<Button id="buttonShake" text="Tap to shake, rattle n' pop" tap="{{ onTapAnything }}" class="btn btn-primary btn-view-demo btn-lime" touchAnimation="{{ touchAnimationNative }}" />
|
||||||
|
<StackLayout id="stack1" rows="auto" columns="*,auto,auto,*" class="p-10 m-y-10" tap="{{ onTapAnything }}" touchAnimation="{{ touchAnimationLayout }}" borderRadius="8" borderWidth="1" borderColor="#999">
|
||||||
|
<ContentView col="1" backgroundColor="orange" borderRadius="10" width="20" height="20" verticalAlignment="middle" />
|
||||||
|
<Label col="2" text="Touchable StackLayout" class="t-18 text-center" verticalAlignment="middle" />
|
||||||
|
</StackLayout>
|
||||||
|
<Button id="button2" text="Auto animation w/ TouchManager" tap="{{ onTapAnything }}" class="btn btn-primary btn-view-demo" touchAnimation="true" />
|
||||||
|
<Button id="button3" text="Touch animation ignored" tap="{{ onTapAnything }}" class="btn btn-primary btn-view-demo" ignoreTouchAnimation="true" isEnabled="false" />
|
||||||
|
<Button id="button4" text="Touch rotate" tap="{{ onTapAnything }}" class="btn btn-primary btn-view-demo btn-ruby" touchAnimation="{{ touchAnimationRotate }}" />
|
||||||
|
<Button id="button5" text="Touch grow, slow return" tap="{{ onTapAnything }}" class="btn btn-primary btn-view-demo btn-forest" touchAnimation="{{ touchAnimationGrow }}" />
|
||||||
|
<Button id="button6" text="Touch me, I'm a lil' shifty!" tap="{{ onTapAnything }}" class="btn btn-primary btn-view-demo btn-orange" touchAnimation="{{ touchAnimationBlowAway }}" />
|
||||||
|
|
||||||
|
<!-- uncomment the following along with ScrollView to test behavior in ScrollView -->
|
||||||
|
<!-- <Button text="TAP" tap="{{ onTapAnything }}" class="btn btn-primary btn-view-demo" touchAnimation="true" />
|
||||||
|
<Button text="TAP" tap="{{ onTapAnything }}" class="btn btn-primary btn-view-demo" touchAnimation="true" />
|
||||||
|
<Button text="TAP" tap="{{ onTapAnything }}" class="btn btn-primary btn-view-demo" touchAnimation="true" />
|
||||||
|
<Button text="TAP" tap="{{ onTapAnything }}" class="btn btn-primary btn-view-demo" touchAnimation="true" />
|
||||||
|
<Button text="TAP" tap="{{ onTapAnything }}" class="btn btn-primary btn-view-demo" touchAnimation="true" />
|
||||||
|
<Button text="TAP" tap="{{ onTapAnything }}" class="btn btn-primary btn-view-demo" touchAnimation="true" />
|
||||||
|
<Button text="TAP" tap="{{ onTapAnything }}" class="btn btn-primary btn-view-demo" touchAnimation="true" />
|
||||||
|
<Button text="TAP" tap="{{ onTapAnything }}" class="btn btn-primary btn-view-demo" touchAnimation="true" /> -->
|
||||||
|
|
||||||
|
</StackLayout>
|
||||||
|
<!-- </ScrollView> -->
|
||||||
|
</Page>
|
@ -31,6 +31,20 @@ export class TouchManager {
|
|||||||
/**
|
/**
|
||||||
* Define reusable touch animations to use on views with touchAnimation defined or with enableGlobalTapAnimations on.
|
* Define reusable touch animations to use on views with touchAnimation defined or with enableGlobalTapAnimations on.
|
||||||
*/
|
*/
|
||||||
|
// Note: In the future, we may expand this to allow an Array of "named" animations to collect an entire suite of custom app animations. Combined with a new 'touch-action' CSS property which could indicate them by name, for example:
|
||||||
|
// .touch-grow {
|
||||||
|
// touch-action: down-grow up-grow
|
||||||
|
// }
|
||||||
|
// TouchManager.animations = {
|
||||||
|
// down: [
|
||||||
|
// { name: grow, (view: View) => { /* animations */ } },
|
||||||
|
// { name: pop, (view: View) => { /* animations */ } }
|
||||||
|
// ],
|
||||||
|
// up: [
|
||||||
|
// { name: grow, (view: View) => { /* animations */ } },
|
||||||
|
// { name: pop, (view: View) => { /* animations */ } }
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
static animations: TouchAnimationOptions;
|
static animations: TouchAnimationOptions;
|
||||||
/**
|
/**
|
||||||
* Native Touch handlers (iOS only) registered with the view through the TouchManager.
|
* Native Touch handlers (iOS only) registered with the view through the TouchManager.
|
||||||
|
Reference in New Issue
Block a user