Merge pull request #2222 from NativeScript/hardware-animations

Enable hardware acceleration for views animations in Android
This commit is contained in:
Rossen Hristov
2016-06-01 09:15:15 +03:00
3 changed files with 48 additions and 25 deletions

View File

@ -7,6 +7,7 @@ import types = require("utils/types");
import enums = require("ui/enums");
import styleModule = require("ui/styling/style");
import lazy from "utils/lazy";
import { CacheLayerType } from "utils/utils";
global.moduleMerge(common, exports);
@ -41,29 +42,22 @@ export class Animation extends common.Animation implements definition.Animation
public play(): definition.AnimationPromise {
let animationFinishedPromise = super.play();
let i: number;
let length: number;
this._animators = new Array<android.animation.Animator>();
this._propertyUpdateCallbacks = new Array<Function>();
this._propertyResetCallbacks = new Array<Function>();
i = 0;
length = this._propertyAnimations.length;
for (; i < length; i++) {
for (let i = 0, length = this._propertyAnimations.length; i < length; i++) {
this._createAnimators(this._propertyAnimations[i]);
}
this._nativeAnimatorsArray = (<any>Array).create(android.animation.Animator, this._animators.length);
i = 0;
length = this._animators.length;
for (; i < length; i++) {
for (let i = 0, length = this._animators.length; i < length; i++) {
this._nativeAnimatorsArray[i] = this._animators[i];
}
this._animatorSet = new android.animation.AnimatorSet();
this._animatorSet.addListener(this._animatorListener);
if (length > 0) {
if (this._animators.length > 0) {
if (this._playSequentially) {
this._animatorSet.playSequentially(this._nativeAnimatorsArray);
}
@ -72,6 +66,8 @@ export class Animation extends common.Animation implements definition.Animation
}
}
this._enableHardwareAcceleration();
if (trace.enabled) {
trace.write("Starting " + this._nativeAnimatorsArray.length + " animations " + (this._playSequentially ? "sequentially." : "together."), trace.categories.Animation);
}
@ -79,7 +75,7 @@ export class Animation extends common.Animation implements definition.Animation
this._animatorSet.start();
return animationFinishedPromise;
}
public cancel(): void {
super.cancel();
if (trace.enabled) {
@ -133,6 +129,7 @@ export class Animation extends common.Animation implements definition.Animation
for (; i < length; i++) {
this._propertyUpdateCallbacks[i]();
}
this._disableHardwareAcceleration();
this._resolveAnimationFinishedPromise();
}
@ -142,11 +139,11 @@ export class Animation extends common.Animation implements definition.Animation
for (; i < length; i++) {
this._propertyResetCallbacks[i]();
}
this._disableHardwareAcceleration();
this._rejectAnimationFinishedPromise();
}
private _createAnimators(propertyAnimation: common.PropertyAnimation): void {
if (!propertyAnimation.target._nativeView) {
return;
}
@ -168,7 +165,7 @@ export class Animation extends common.Animation implements definition.Animation
}
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 propertyUpdateCallbacks = 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 {
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));
@ -422,4 +440,4 @@ export function _resolveAnimationCurve(curve: any): any {
}
return curve;
}
}
}

View File

@ -5,6 +5,7 @@ import view = require("ui/core/view");
import types = require("utils/types");
import * as styleModule from "./style";
import * as buttonModule from "ui/button";
import { CacheLayerType } from "utils/utils";
//@private
declare module "ui/styling/background" {
@ -238,10 +239,6 @@ export module ad {
var _defaultBackgrounds = new Map<string, android.graphics.drawable.Drawable>();
interface CacheLayerType {
layerType: number;
}
export function onBackgroundOrBorderPropertyChanged(v: view.View) {
var nativeView = <android.view.View>v._nativeView;
var cache = <CacheLayerType>v._nativeView;
@ -266,8 +263,8 @@ export module ad {
let backgroundColor = bkg.backgroundColor = v.style._getValue(style.backgroundColorProperty).android;
bkg.setColorFilter(backgroundColor, android.graphics.PorterDuff.Mode.SRC_IN);
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)) {
bkg = new BorderDrawableClass();
let viewClass = types.getClass(v);
@ -284,11 +281,11 @@ export module ad {
bkg.background = backgroundValue;
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:
// http://developer.android.com/guide/topics/graphics/hardware-accel.html
cache.layerType = nativeView.getLayerType();
nativeView.setLayerType(android.view.View.LAYER_TYPE_SOFTWARE, null);
cache.layerType = cache.getLayerType();
cache.setLayerType(android.view.View.LAYER_TYPE_SOFTWARE, null);
}
}
else {
@ -305,8 +302,7 @@ export module ad {
}
if (cache.layerType !== undefined) {
// Reset layer type
nativeView.setLayerType(cache.layerType, null);
cache.setLayerType(cache.layerType, null);
cache.layerType = undefined;
}
}

View File

@ -10,6 +10,15 @@
interface Owned {
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
/**