feat(android): migrate to support library apis (#6129)

Switch Activity / Fragment / FragmentManager implementation from native framework to support library APIs

BREAKING CHANGE:


NativeScript core framework now extends support library APIs versus native framework classes as per Google's latest guidelines:
- NativeScript activities now extend `android.support.v7.app.AppCompatActivity` (vs android.app.Activity)
- NativeScript fragments now extend `android.support.v4.app.Fragment` (vs android.app.Fragment)
- NativeScript now works internally with `android.support.v4.app.FragmentManager` (vs android.app.FragmentManager) 

The implications of these changes should be mostly transparent to the developer except for the fact that the support library Fragment / FragmentManager work with Animation APIs versus Animator APIs.

For Android API Levels lower than 28 the new Fragment API uses a different fragment enter animation by default. You can customise the transition per navigation entry or globally via the [navigation transitions API](https://docs.nativescript.org/core-concepts/navigation#navigation-transitions)
Before:
Default fragment enter animation was fade animation

After:
Default fragment enter animation for API levels lower than 28 is now a fast "push fade" animation; default fragment enter animation for API levels equal to or greater than 28 remains fade animation

Before:
AndroidFragmentCallbacks interface exposed the following `onCreateAnimator(...)` method
``` ts
export interface AndroidFragmentCallbacks {
    onCreateAnimator(fragment: any, transit: number, enter: boolean, nextAnim: number, superFunc: Function): any;
    // ...
}
```

After:
AndroidFragmentCallbacks interface now exposes the following `onCreateAnimation(...)` method instead (and `onCreateAnimator(...)` is now removed)
``` ts
export interface AndroidFragmentCallbacks {
    onCreateAnimation(fragment: any, transit: number, enter: boolean, nextAnim: number, superFunc: Function): any;
    // ...
}
```

Before:
Transition class exposed the following abstract `createAndroidAnimator(...)` method
``` ts
export class Transition {
    public createAndroidAnimator(transitionType: string): any;
    // ...
}
```

After:
Transition class now exposes the following abstract `createAndroidAnimation(...)` method instead (and `createAndroidAnimation(...) is now removed)
``` ts
export class Transition {
    public createAndroidAnimation(transitionType: string): any;
    // ...
}
```

To migrate the code of your custom transitions follow the example below:

Before:
``` ts
import * as transition from "tns-core-modules/ui/transition";

export class CustomTransition extends transition.Transition {
    constructor(duration: number, curve: any) {
        super(duration, curve);
    }

    public createAndroidAnimator(transitionType: string): android.animation.Animator {
        var scaleValues = Array.create("float", 2);
        switch (transitionType) {
            case transition.AndroidTransitionType.enter:
            case transition.AndroidTransitionType.popEnter:
                scaleValues[0] = 0;
                scaleValues[1] = 1;
                break;
            case transition.AndroidTransitionType.exit:
            case transition.AndroidTransitionType.popExit:
                scaleValues[0] = 1;
                scaleValues[1] = 0;
                break;
        }
        var objectAnimators = Array.create(android.animation.Animator, 2);
        objectAnimators[0] = android.animation.ObjectAnimator.ofFloat(null, "scaleX", scaleValues);
        objectAnimators[1] = android.animation.ObjectAnimator.ofFloat(null, "scaleY", scaleValues);
        var animatorSet = new android.animation.AnimatorSet();
        animatorSet.playTogether(objectAnimators);

        var duration = this.getDuration();
        if (duration !== undefined) {
            animatorSet.setDuration(duration);
        }
        animatorSet.setInterpolator(this.getCurve());

        return animatorSet;
    }
}
```

After:
``` ts
import * as transition from "tns-core-modules/ui/transition";

export class CustomTransition extends transition.Transition {
    constructor(duration: number, curve: any) {
        super(duration, curve);
    }

    public createAndroidAnimation(transitionType: string): android.view.animation.Animation {
        const scaleValues = [];

        switch (transitionType) {
            case transition.AndroidTransitionType.enter:
            case transition.AndroidTransitionType.popEnter:
                scaleValues[0] = 0;
                scaleValues[1] = 1;
                break;
            case transition.AndroidTransitionType.exit:
            case transition.AndroidTransitionType.popExit:
                scaleValues[0] = 1;
                scaleValues[1] = 0;
                break;
        }
            
        const animationSet = new android.view.animation.AnimationSet(false);
        const duration = this.getDuration();
        if (duration !== undefined) {
            animationSet.setDuration(duration);
        }

        animationSet.setInterpolator(this.getCurve());
        animationSet.addAnimation(
            new android.view.animation.ScaleAnimation(
                scaleValues[0], 
                scaleValues[1], 
                scaleValues[0], 
                scaleValues[1]
            ));

        return animationSet;
    }
}
```
This commit is contained in:
Manol Donev
2018-07-31 18:48:34 +03:00
committed by GitHub
parent 5db3e67915
commit cf034dd04d
21 changed files with 339 additions and 323 deletions

View File

@@ -47,7 +47,7 @@ interface TouchListener {
}
interface DialogFragment {
new(): android.app.DialogFragment;
new(): android.support.v4.app.DialogFragment;
}
function initializeDisabledListener(): void {
@@ -120,7 +120,7 @@ function initializeDialogFragment() {
}
}
class DialogFragmentImpl extends android.app.DialogFragment {
class DialogFragmentImpl extends android.support.v4.app.DialogFragment {
public owner: View;
private _fullscreen: boolean;
private _stretched: boolean;
@@ -141,7 +141,7 @@ function initializeDialogFragment() {
this._dismissCallback = options.dismissCallback;
this._shownCallback = options.shownCallback;
this.owner._dialogFragment = this;
this.setStyle(android.app.DialogFragment.STYLE_NO_TITLE, 0);
this.setStyle(android.support.v4.app.DialogFragment.STYLE_NO_TITLE, 0);
const dialog = new DialogImpl(this, this.getActivity(), this.getTheme());
@@ -225,13 +225,13 @@ function getModalOptions(domId: number): DialogOptions {
export class View extends ViewCommon {
public static androidBackPressedEvent = androidBackPressedEvent;
public _dialogFragment: android.app.DialogFragment;
public _dialogFragment: android.support.v4.app.DialogFragment;
private _isClickable: boolean;
private touchListenerIsSet: boolean;
private touchListener: android.view.View.OnTouchListener;
private layoutChangeListenerIsSet: boolean;
private layoutChangeListener: android.view.View.OnLayoutChangeListener;
private _manager: android.app.FragmentManager;
private _manager: android.support.v4.app.FragmentManager;
nativeViewProtected: android.view.View;
@@ -263,7 +263,7 @@ export class View extends ViewCommon {
}
}
public _getFragmentManager(): android.app.FragmentManager {
public _getFragmentManager(): android.support.v4.app.FragmentManager {
let manager = this._manager;
if (!manager) {
let view: View = this;
@@ -280,7 +280,7 @@ export class View extends ViewCommon {
}
if (!manager && this._context) {
manager = (<android.app.Activity>this._context).getFragmentManager();
manager = (<android.support.v7.app.AppCompatActivity>this._context).getSupportFragmentManager();
}
this._manager = manager;

View File

@@ -659,7 +659,7 @@ export abstract class View extends ViewBase {
/**
* @private
*/
_getFragmentManager(): any; /* android.app.FragmentManager */
_getFragmentManager(): any; /* android.support.v4.app.FragmentManager */
/**
* Updates styleScope or create new styleScope.