Merge pull request #3931 from NativeScript/fix-ios-animations

Fix iOS animations, transition was workin in DIP, when css class is change objects were flickering
This commit is contained in:
Panayot Cankov
2017-04-04 13:50:26 +03:00
committed by GitHub
6 changed files with 60 additions and 24 deletions

View File

@ -1,5 +1,5 @@
import { AnimationDefinition } from ".";
import { View } from "../core/view";
import { View, layout } from "../core/view";
import { AnimationBase, Properties, PropertyAnimation, CubicBezierAnimationCurve, AnimationPromise, traceWrite, traceEnabled, traceCategories } from "./animation-common";
import {
@ -589,7 +589,9 @@ export class Animation extends AnimationBase {
export function _getTransformMismatchErrorMessage(view: View): string {
// Order is important: translate, rotate, scale
let result: CGAffineTransform = CGAffineTransformIdentity;
result = CGAffineTransformTranslate(result, Length.toDevicePixels(view.translateX || 0, 0), Length.toDevicePixels(view.translateY || 0, 0));
const tx = layout.toDeviceIndependentPixels(Length.toDevicePixels(view.translateX || 0, 0));
const ty = layout.toDeviceIndependentPixels(Length.toDevicePixels(view.translateY || 0, 0));
result = CGAffineTransformTranslate(result, tx, ty);
result = CGAffineTransformRotate(result, (view.rotate || 0) * Math.PI / 180);
result = CGAffineTransformScale(result, view.scaleX || 1, view.scaleY || 1);
let viewTransform = NSStringFromCGAffineTransform(result);

View File

@ -247,6 +247,19 @@ export abstract class ViewBase extends Observable {
//@private
public _styleScope: any;
/**
* Determines the depth of batchUpdates.
* When the value is 0 the current updates are not batched.
* If the value is 1 or greater, the current updates are batched.
* Do not set this field, the _batchUpdate method is responsible to keep the count up to date.
*/
public _batchUpdateScope: number;
/**
* Allow multiple updates to be performed on the instance at once.
*/
public _batchUpdate<T>(callback: () => T): T;
//@endprivate
}

View File

@ -279,6 +279,16 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
this._emit("unloaded");
}
public _batchUpdateScope: number;
public _batchUpdate<T>(callback: () => T): T {
try {
++this._batchUpdateScope;
return callback();
} finally {
--this._batchUpdateScope;
}
}
private _unloadEachChild() {
this.eachChild((child) => {
if (child.isLoaded) {
@ -371,13 +381,14 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
private _invalidateCssHandlerSuspended: boolean;
private applyCssState(): void {
if (!this._cssState) {
return;
}
// this.style._beginUpdate();
this._cssState.apply();
// this.style._endUpdate();
this._batchUpdate(() => {
if (!this._cssState) {
this._cancelAllAnimations();
resetCSSProperties(this.style);
return;
}
this._cssState.apply();
});
}
private pseudoClassAliases = {
@ -847,6 +858,8 @@ ViewBase.prototype._defaultPaddingRight = 0;
ViewBase.prototype._defaultPaddingBottom = 0;
ViewBase.prototype._defaultPaddingLeft = 0;
ViewBase.prototype._batchUpdateScope = 0;
export const bindingContextProperty = new InheritedProperty<ViewBase, any>({ name: "bindingContext" });
bindingContextProperty.register(ViewBase);
@ -864,8 +877,6 @@ export const classNameProperty = new Property<ViewBase, string>({
classNameProperty.register(ViewBase);
function resetStyles(view: ViewBase): void {
view._cancelAllAnimations();
resetCSSProperties(view.style);
view._applyStyleFromScope();
view.eachChild((child) => {
resetStyles(child);

View File

@ -231,8 +231,8 @@ export class View extends ViewCommon {
}
public updateNativeTransform() {
let translateX = Length.toDevicePixels(this.translateX || 0, 0);
let translateY = Length.toDevicePixels(this.translateY || 0, 0);
let translateX = layout.toDeviceIndependentPixels(Length.toDevicePixels(this.translateX || 0, 0));
let translateY = layout.toDeviceIndependentPixels(Length.toDevicePixels(this.translateY || 0, 0));
let scaleX = this.scaleX || 1;
let scaleY = this.scaleY || 1;
let rotate = this.rotate || 0;
@ -241,8 +241,15 @@ export class View extends ViewCommon {
newTransform = CGAffineTransformRotate(newTransform, rotate * Math.PI / 180);
newTransform = CGAffineTransformScale(newTransform, scaleX === 0 ? 0.001 : scaleX, scaleY === 0 ? 0.001 : scaleY);
if (!CGAffineTransformEqualToTransform(this.nativeView.transform, newTransform)) {
let updateSuspended = this._isPresentationLayerUpdateSuspeneded();
if (!updateSuspended) {
CATransaction.begin();
}
this.nativeView.transform = newTransform;
this._hasTransfrom = this.nativeView && !CGAffineTransformEqualToTransform(this.nativeView.transform, CGAffineTransformIdentity);
if (!updateSuspended) {
CATransaction.commit();
}
}
}
@ -266,7 +273,7 @@ export class View extends ViewCommon {
}
public _isPresentationLayerUpdateSuspeneded() {
return this._suspendCATransaction;
return this._suspendCATransaction || this._batchUpdateScope;
}
[isEnabledProperty.getDefault](): boolean {

View File

@ -102,11 +102,12 @@ export class CssState {
matchingSelectors.push(this.view.inlineStyleSelector);
}
matchingSelectors.forEach(s => this.applyDescriptors(this.view, s.ruleset));
matchingSelectors.forEach(s => this.applyDescriptors(s.ruleset));
matchingSelectors.forEach(s => this.playKeyframeAnimations(s.ruleset));
}
private applyDescriptors(view: ViewBase, ruleset: RuleSet): void {
let style = view.style;
private applyDescriptors(ruleset: RuleSet): void {
let style = this.view.style;
ruleset.declarations.forEach(d => {
try {
// Use the "css:" prefixed name, so that CSS value source is set.
@ -114,23 +115,25 @@ export class CssState {
if (cssPropName in style) {
style[cssPropName] = d.value;
} else {
view[d.property] = d.value;
this.view[d.property] = d.value;
}
} catch (e) {
traceWrite(`Failed to apply property [${d.property}] with value [${d.value}] to ${view}. ${e}`, traceCategories.Error, traceMessageType.error);
traceWrite(`Failed to apply property [${d.property}] with value [${d.value}] to ${this.view}. ${e}`, traceCategories.Error, traceMessageType.error);
}
});
}
private playKeyframeAnimations(ruleset: RuleSet): void {
let ruleAnimations: kam.KeyframeAnimationInfo[] = ruleset[animationsSymbol];
if (ruleAnimations) {
ensureKeyframeAnimationModule();
for (let animationInfo of ruleAnimations) {
let animation = keyframeAnimationModule.KeyframeAnimation.keyframeAnimationFromInfo(animationInfo);
if (animation) {
view._registerAnimation(animation);
animation.play(<View>view)
.then(() => { view._unregisterAnimation(animation); })
.catch((e) => { view._unregisterAnimation(animation); });
this.view._registerAnimation(animation);
animation.play(<View>this.view)
.then(() => { this.view._unregisterAnimation(animation); })
.catch((e) => { this.view._unregisterAnimation(animation); });
}
}
}

View File

@ -20,7 +20,7 @@ export class Transition {
//@private
export function _clearBackwardTransitions(fragment: any): void;
export function _clearForwardTransitions(fragment: any): void;
export function _setAndroidFragmentTransitions(cachePagesOnNavigate: boolean, navigationTransition: NavigationTransition, currentFragment: any, newFragment: any, fragmentTransaction: android.app.FragmentTransaction): void;
export function _setAndroidFragmentTransitions(cachePagesOnNavigate: boolean, navigationTransition: NavigationTransition, currentFragment: any, newFragment: any, fragmentTransaction: any): void;
export function _onFragmentCreateAnimator(fragment: any, nextAnim: number): any;
export function _onFragmentShown(fragment: any, isBack: boolean): void;
export function _onFragmentHidden(fragment: any, isBack: boolean, destroyed: boolean): void;