mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-18 05:18:39 +08:00
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:
@ -1,5 +1,5 @@
|
|||||||
import { AnimationDefinition } from ".";
|
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 { AnimationBase, Properties, PropertyAnimation, CubicBezierAnimationCurve, AnimationPromise, traceWrite, traceEnabled, traceCategories } from "./animation-common";
|
||||||
import {
|
import {
|
||||||
@ -589,7 +589,9 @@ export class Animation extends AnimationBase {
|
|||||||
export function _getTransformMismatchErrorMessage(view: View): string {
|
export function _getTransformMismatchErrorMessage(view: View): string {
|
||||||
// Order is important: translate, rotate, scale
|
// Order is important: translate, rotate, scale
|
||||||
let result: CGAffineTransform = CGAffineTransformIdentity;
|
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 = CGAffineTransformRotate(result, (view.rotate || 0) * Math.PI / 180);
|
||||||
result = CGAffineTransformScale(result, view.scaleX || 1, view.scaleY || 1);
|
result = CGAffineTransformScale(result, view.scaleX || 1, view.scaleY || 1);
|
||||||
let viewTransform = NSStringFromCGAffineTransform(result);
|
let viewTransform = NSStringFromCGAffineTransform(result);
|
||||||
|
@ -247,6 +247,19 @@ export abstract class ViewBase extends Observable {
|
|||||||
|
|
||||||
//@private
|
//@private
|
||||||
public _styleScope: any;
|
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
|
//@endprivate
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,6 +279,16 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
|
|||||||
this._emit("unloaded");
|
this._emit("unloaded");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public _batchUpdateScope: number;
|
||||||
|
public _batchUpdate<T>(callback: () => T): T {
|
||||||
|
try {
|
||||||
|
++this._batchUpdateScope;
|
||||||
|
return callback();
|
||||||
|
} finally {
|
||||||
|
--this._batchUpdateScope;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private _unloadEachChild() {
|
private _unloadEachChild() {
|
||||||
this.eachChild((child) => {
|
this.eachChild((child) => {
|
||||||
if (child.isLoaded) {
|
if (child.isLoaded) {
|
||||||
@ -371,13 +381,14 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
|
|||||||
private _invalidateCssHandlerSuspended: boolean;
|
private _invalidateCssHandlerSuspended: boolean;
|
||||||
|
|
||||||
private applyCssState(): void {
|
private applyCssState(): void {
|
||||||
|
this._batchUpdate(() => {
|
||||||
if (!this._cssState) {
|
if (!this._cssState) {
|
||||||
|
this._cancelAllAnimations();
|
||||||
|
resetCSSProperties(this.style);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// this.style._beginUpdate();
|
|
||||||
this._cssState.apply();
|
this._cssState.apply();
|
||||||
// this.style._endUpdate();
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private pseudoClassAliases = {
|
private pseudoClassAliases = {
|
||||||
@ -847,6 +858,8 @@ ViewBase.prototype._defaultPaddingRight = 0;
|
|||||||
ViewBase.prototype._defaultPaddingBottom = 0;
|
ViewBase.prototype._defaultPaddingBottom = 0;
|
||||||
ViewBase.prototype._defaultPaddingLeft = 0;
|
ViewBase.prototype._defaultPaddingLeft = 0;
|
||||||
|
|
||||||
|
ViewBase.prototype._batchUpdateScope = 0;
|
||||||
|
|
||||||
export const bindingContextProperty = new InheritedProperty<ViewBase, any>({ name: "bindingContext" });
|
export const bindingContextProperty = new InheritedProperty<ViewBase, any>({ name: "bindingContext" });
|
||||||
bindingContextProperty.register(ViewBase);
|
bindingContextProperty.register(ViewBase);
|
||||||
|
|
||||||
@ -864,8 +877,6 @@ export const classNameProperty = new Property<ViewBase, string>({
|
|||||||
classNameProperty.register(ViewBase);
|
classNameProperty.register(ViewBase);
|
||||||
|
|
||||||
function resetStyles(view: ViewBase): void {
|
function resetStyles(view: ViewBase): void {
|
||||||
view._cancelAllAnimations();
|
|
||||||
resetCSSProperties(view.style);
|
|
||||||
view._applyStyleFromScope();
|
view._applyStyleFromScope();
|
||||||
view.eachChild((child) => {
|
view.eachChild((child) => {
|
||||||
resetStyles(child);
|
resetStyles(child);
|
||||||
|
@ -231,8 +231,8 @@ export class View extends ViewCommon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public updateNativeTransform() {
|
public updateNativeTransform() {
|
||||||
let translateX = Length.toDevicePixels(this.translateX || 0, 0);
|
let translateX = layout.toDeviceIndependentPixels(Length.toDevicePixels(this.translateX || 0, 0));
|
||||||
let translateY = Length.toDevicePixels(this.translateY || 0, 0);
|
let translateY = layout.toDeviceIndependentPixels(Length.toDevicePixels(this.translateY || 0, 0));
|
||||||
let scaleX = this.scaleX || 1;
|
let scaleX = this.scaleX || 1;
|
||||||
let scaleY = this.scaleY || 1;
|
let scaleY = this.scaleY || 1;
|
||||||
let rotate = this.rotate || 0;
|
let rotate = this.rotate || 0;
|
||||||
@ -241,8 +241,15 @@ export class View extends ViewCommon {
|
|||||||
newTransform = CGAffineTransformRotate(newTransform, rotate * Math.PI / 180);
|
newTransform = CGAffineTransformRotate(newTransform, rotate * Math.PI / 180);
|
||||||
newTransform = CGAffineTransformScale(newTransform, scaleX === 0 ? 0.001 : scaleX, scaleY === 0 ? 0.001 : scaleY);
|
newTransform = CGAffineTransformScale(newTransform, scaleX === 0 ? 0.001 : scaleX, scaleY === 0 ? 0.001 : scaleY);
|
||||||
if (!CGAffineTransformEqualToTransform(this.nativeView.transform, newTransform)) {
|
if (!CGAffineTransformEqualToTransform(this.nativeView.transform, newTransform)) {
|
||||||
|
let updateSuspended = this._isPresentationLayerUpdateSuspeneded();
|
||||||
|
if (!updateSuspended) {
|
||||||
|
CATransaction.begin();
|
||||||
|
}
|
||||||
this.nativeView.transform = newTransform;
|
this.nativeView.transform = newTransform;
|
||||||
this._hasTransfrom = this.nativeView && !CGAffineTransformEqualToTransform(this.nativeView.transform, CGAffineTransformIdentity);
|
this._hasTransfrom = this.nativeView && !CGAffineTransformEqualToTransform(this.nativeView.transform, CGAffineTransformIdentity);
|
||||||
|
if (!updateSuspended) {
|
||||||
|
CATransaction.commit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,7 +273,7 @@ export class View extends ViewCommon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public _isPresentationLayerUpdateSuspeneded() {
|
public _isPresentationLayerUpdateSuspeneded() {
|
||||||
return this._suspendCATransaction;
|
return this._suspendCATransaction || this._batchUpdateScope;
|
||||||
}
|
}
|
||||||
|
|
||||||
[isEnabledProperty.getDefault](): boolean {
|
[isEnabledProperty.getDefault](): boolean {
|
||||||
|
@ -102,11 +102,12 @@ export class CssState {
|
|||||||
matchingSelectors.push(this.view.inlineStyleSelector);
|
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 {
|
private applyDescriptors(ruleset: RuleSet): void {
|
||||||
let style = view.style;
|
let style = this.view.style;
|
||||||
ruleset.declarations.forEach(d => {
|
ruleset.declarations.forEach(d => {
|
||||||
try {
|
try {
|
||||||
// Use the "css:" prefixed name, so that CSS value source is set.
|
// Use the "css:" prefixed name, so that CSS value source is set.
|
||||||
@ -114,23 +115,25 @@ export class CssState {
|
|||||||
if (cssPropName in style) {
|
if (cssPropName in style) {
|
||||||
style[cssPropName] = d.value;
|
style[cssPropName] = d.value;
|
||||||
} else {
|
} else {
|
||||||
view[d.property] = d.value;
|
this.view[d.property] = d.value;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} 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];
|
let ruleAnimations: kam.KeyframeAnimationInfo[] = ruleset[animationsSymbol];
|
||||||
if (ruleAnimations) {
|
if (ruleAnimations) {
|
||||||
ensureKeyframeAnimationModule();
|
ensureKeyframeAnimationModule();
|
||||||
for (let animationInfo of ruleAnimations) {
|
for (let animationInfo of ruleAnimations) {
|
||||||
let animation = keyframeAnimationModule.KeyframeAnimation.keyframeAnimationFromInfo(animationInfo);
|
let animation = keyframeAnimationModule.KeyframeAnimation.keyframeAnimationFromInfo(animationInfo);
|
||||||
if (animation) {
|
if (animation) {
|
||||||
view._registerAnimation(animation);
|
this.view._registerAnimation(animation);
|
||||||
animation.play(<View>view)
|
animation.play(<View>this.view)
|
||||||
.then(() => { view._unregisterAnimation(animation); })
|
.then(() => { this.view._unregisterAnimation(animation); })
|
||||||
.catch((e) => { view._unregisterAnimation(animation); });
|
.catch((e) => { this.view._unregisterAnimation(animation); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ export class Transition {
|
|||||||
//@private
|
//@private
|
||||||
export function _clearBackwardTransitions(fragment: any): void;
|
export function _clearBackwardTransitions(fragment: any): void;
|
||||||
export function _clearForwardTransitions(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 _onFragmentCreateAnimator(fragment: any, nextAnim: number): any;
|
||||||
export function _onFragmentShown(fragment: any, isBack: boolean): void;
|
export function _onFragmentShown(fragment: any, isBack: boolean): void;
|
||||||
export function _onFragmentHidden(fragment: any, isBack: boolean, destroyed: boolean): void;
|
export function _onFragmentHidden(fragment: any, isBack: boolean, destroyed: boolean): void;
|
||||||
|
Reference in New Issue
Block a user