mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-15 19:26:42 +08:00
Merge pull request #2222 from NativeScript/hardware-animations
Enable hardware acceleration for views animations in Android
This commit is contained in:
@ -7,6 +7,7 @@ import types = require("utils/types");
|
|||||||
import enums = require("ui/enums");
|
import enums = require("ui/enums");
|
||||||
import styleModule = require("ui/styling/style");
|
import styleModule = require("ui/styling/style");
|
||||||
import lazy from "utils/lazy";
|
import lazy from "utils/lazy";
|
||||||
|
import { CacheLayerType } from "utils/utils";
|
||||||
|
|
||||||
global.moduleMerge(common, exports);
|
global.moduleMerge(common, exports);
|
||||||
|
|
||||||
@ -41,29 +42,22 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
public play(): definition.AnimationPromise {
|
public play(): definition.AnimationPromise {
|
||||||
let animationFinishedPromise = super.play();
|
let animationFinishedPromise = super.play();
|
||||||
|
|
||||||
let i: number;
|
|
||||||
let length: number;
|
|
||||||
|
|
||||||
this._animators = new Array<android.animation.Animator>();
|
this._animators = new Array<android.animation.Animator>();
|
||||||
this._propertyUpdateCallbacks = new Array<Function>();
|
this._propertyUpdateCallbacks = new Array<Function>();
|
||||||
this._propertyResetCallbacks = new Array<Function>();
|
this._propertyResetCallbacks = new Array<Function>();
|
||||||
|
|
||||||
i = 0;
|
for (let i = 0, length = this._propertyAnimations.length; i < length; i++) {
|
||||||
length = this._propertyAnimations.length;
|
|
||||||
for (; i < length; i++) {
|
|
||||||
this._createAnimators(this._propertyAnimations[i]);
|
this._createAnimators(this._propertyAnimations[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._nativeAnimatorsArray = (<any>Array).create(android.animation.Animator, this._animators.length);
|
this._nativeAnimatorsArray = (<any>Array).create(android.animation.Animator, this._animators.length);
|
||||||
i = 0;
|
for (let i = 0, length = this._animators.length; i < length; i++) {
|
||||||
length = this._animators.length;
|
|
||||||
for (; i < length; i++) {
|
|
||||||
this._nativeAnimatorsArray[i] = this._animators[i];
|
this._nativeAnimatorsArray[i] = this._animators[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
this._animatorSet = new android.animation.AnimatorSet();
|
this._animatorSet = new android.animation.AnimatorSet();
|
||||||
this._animatorSet.addListener(this._animatorListener);
|
this._animatorSet.addListener(this._animatorListener);
|
||||||
if (length > 0) {
|
if (this._animators.length > 0) {
|
||||||
if (this._playSequentially) {
|
if (this._playSequentially) {
|
||||||
this._animatorSet.playSequentially(this._nativeAnimatorsArray);
|
this._animatorSet.playSequentially(this._nativeAnimatorsArray);
|
||||||
}
|
}
|
||||||
@ -72,6 +66,8 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._enableHardwareAcceleration();
|
||||||
|
|
||||||
if (trace.enabled) {
|
if (trace.enabled) {
|
||||||
trace.write("Starting " + this._nativeAnimatorsArray.length + " animations " + (this._playSequentially ? "sequentially." : "together."), trace.categories.Animation);
|
trace.write("Starting " + this._nativeAnimatorsArray.length + " animations " + (this._playSequentially ? "sequentially." : "together."), trace.categories.Animation);
|
||||||
}
|
}
|
||||||
@ -133,6 +129,7 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
for (; i < length; i++) {
|
for (; i < length; i++) {
|
||||||
this._propertyUpdateCallbacks[i]();
|
this._propertyUpdateCallbacks[i]();
|
||||||
}
|
}
|
||||||
|
this._disableHardwareAcceleration();
|
||||||
this._resolveAnimationFinishedPromise();
|
this._resolveAnimationFinishedPromise();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,11 +139,11 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
for (; i < length; i++) {
|
for (; i < length; i++) {
|
||||||
this._propertyResetCallbacks[i]();
|
this._propertyResetCallbacks[i]();
|
||||||
}
|
}
|
||||||
|
this._disableHardwareAcceleration();
|
||||||
this._rejectAnimationFinishedPromise();
|
this._rejectAnimationFinishedPromise();
|
||||||
}
|
}
|
||||||
|
|
||||||
private _createAnimators(propertyAnimation: common.PropertyAnimation): void {
|
private _createAnimators(propertyAnimation: common.PropertyAnimation): void {
|
||||||
|
|
||||||
if (!propertyAnimation.target._nativeView) {
|
if (!propertyAnimation.target._nativeView) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -168,7 +165,7 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
}
|
}
|
||||||
|
|
||||||
let nativeArray;
|
let nativeArray;
|
||||||
let nativeView: android.view.View = (<android.view.View>propertyAnimation.target._nativeView);
|
let nativeView = <android.view.View>propertyAnimation.target._nativeView;
|
||||||
let animators = new Array<android.animation.Animator>();
|
let animators = new Array<android.animation.Animator>();
|
||||||
let propertyUpdateCallbacks = new Array<Function>();
|
let propertyUpdateCallbacks = new Array<Function>();
|
||||||
let propertyResetCallbacks = new Array<Function>();
|
let propertyResetCallbacks = new Array<Function>();
|
||||||
@ -375,6 +372,27 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
private static _getAndroidRepeatCount(iterations: number): number {
|
private static _getAndroidRepeatCount(iterations: number): number {
|
||||||
return (iterations === Number.POSITIVE_INFINITY) ? android.view.animation.Animation.INFINITE : iterations - 1;
|
return (iterations === Number.POSITIVE_INFINITY) ? android.view.animation.Animation.INFINITE : iterations - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _enableHardwareAcceleration() {
|
||||||
|
for (let i = 0, length = this._propertyAnimations.length; i < length; i++) {
|
||||||
|
let cache = <CacheLayerType>this._propertyAnimations[i].target._nativeView;
|
||||||
|
let layerType = cache.getLayerType();
|
||||||
|
if (layerType !== android.view.View.LAYER_TYPE_HARDWARE) {
|
||||||
|
cache.layerType = layerType;
|
||||||
|
cache.setLayerType(android.view.View.LAYER_TYPE_HARDWARE, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _disableHardwareAcceleration() {
|
||||||
|
for (let i = 0, length = this._propertyAnimations.length; i < length; i++) {
|
||||||
|
let cache = <CacheLayerType>this._propertyAnimations[i].target._nativeView;
|
||||||
|
if (cache.layerType !== undefined) {
|
||||||
|
cache.setLayerType(cache.layerType, null);
|
||||||
|
cache.layerType = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let easeIn = lazy(() => new android.view.animation.AccelerateInterpolator(1));
|
let easeIn = lazy(() => new android.view.animation.AccelerateInterpolator(1));
|
||||||
|
@ -5,6 +5,7 @@ import view = require("ui/core/view");
|
|||||||
import types = require("utils/types");
|
import types = require("utils/types");
|
||||||
import * as styleModule from "./style";
|
import * as styleModule from "./style";
|
||||||
import * as buttonModule from "ui/button";
|
import * as buttonModule from "ui/button";
|
||||||
|
import { CacheLayerType } from "utils/utils";
|
||||||
|
|
||||||
//@private
|
//@private
|
||||||
declare module "ui/styling/background" {
|
declare module "ui/styling/background" {
|
||||||
@ -238,10 +239,6 @@ export module ad {
|
|||||||
|
|
||||||
var _defaultBackgrounds = new Map<string, android.graphics.drawable.Drawable>();
|
var _defaultBackgrounds = new Map<string, android.graphics.drawable.Drawable>();
|
||||||
|
|
||||||
interface CacheLayerType {
|
|
||||||
layerType: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function onBackgroundOrBorderPropertyChanged(v: view.View) {
|
export function onBackgroundOrBorderPropertyChanged(v: view.View) {
|
||||||
var nativeView = <android.view.View>v._nativeView;
|
var nativeView = <android.view.View>v._nativeView;
|
||||||
var cache = <CacheLayerType>v._nativeView;
|
var cache = <CacheLayerType>v._nativeView;
|
||||||
@ -266,8 +263,8 @@ export module ad {
|
|||||||
let backgroundColor = bkg.backgroundColor = v.style._getValue(style.backgroundColorProperty).android;
|
let backgroundColor = bkg.backgroundColor = v.style._getValue(style.backgroundColorProperty).android;
|
||||||
bkg.setColorFilter(backgroundColor, android.graphics.PorterDuff.Mode.SRC_IN);
|
bkg.setColorFilter(backgroundColor, android.graphics.PorterDuff.Mode.SRC_IN);
|
||||||
bkg.backgroundColor = backgroundColor;
|
bkg.backgroundColor = backgroundColor;
|
||||||
} else if (v.borderWidth !== 0 || v.borderRadius !== 0 || !backgroundValue.isEmpty() || clipPathValue) {
|
}
|
||||||
|
else if (v.borderWidth || v.borderRadius || clipPathValue || !backgroundValue.isEmpty()) {
|
||||||
if (!(bkg instanceof BorderDrawableClass)) {
|
if (!(bkg instanceof BorderDrawableClass)) {
|
||||||
bkg = new BorderDrawableClass();
|
bkg = new BorderDrawableClass();
|
||||||
let viewClass = types.getClass(v);
|
let viewClass = types.getClass(v);
|
||||||
@ -284,11 +281,11 @@ export module ad {
|
|||||||
bkg.background = backgroundValue;
|
bkg.background = backgroundValue;
|
||||||
bkg.clipPath = clipPathValue;
|
bkg.clipPath = clipPathValue;
|
||||||
|
|
||||||
if ((v.borderWidth !== 0 || v.borderRadius !== 0 || clipPathValue) && getSDK() < 18) {
|
if ((v.borderWidth || v.borderRadius || clipPathValue) && getSDK() < 18) {
|
||||||
// Switch to software because of unsupported canvas methods if hardware acceleration is on:
|
// Switch to software because of unsupported canvas methods if hardware acceleration is on:
|
||||||
// http://developer.android.com/guide/topics/graphics/hardware-accel.html
|
// http://developer.android.com/guide/topics/graphics/hardware-accel.html
|
||||||
cache.layerType = nativeView.getLayerType();
|
cache.layerType = cache.getLayerType();
|
||||||
nativeView.setLayerType(android.view.View.LAYER_TYPE_SOFTWARE, null);
|
cache.setLayerType(android.view.View.LAYER_TYPE_SOFTWARE, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -305,8 +302,7 @@ export module ad {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cache.layerType !== undefined) {
|
if (cache.layerType !== undefined) {
|
||||||
// Reset layer type
|
cache.setLayerType(cache.layerType, null);
|
||||||
nativeView.setLayerType(cache.layerType, null);
|
|
||||||
cache.layerType = undefined;
|
cache.layerType = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
9
tns-core-modules/utils/utils.d.ts
vendored
9
tns-core-modules/utils/utils.d.ts
vendored
@ -10,6 +10,15 @@
|
|||||||
interface Owned {
|
interface Owned {
|
||||||
owner: any;
|
owner: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to cache and restore Android views' layer type, i.e. android.view.View.getLayerType and android.view.View.setLayerType.
|
||||||
|
*/
|
||||||
|
interface CacheLayerType {
|
||||||
|
layerType: number;
|
||||||
|
setLayerType(layerType: number, paint: any): void;
|
||||||
|
getLayerType(): number;
|
||||||
|
}
|
||||||
//@endprivate
|
//@endprivate
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user