Repository: NativeScript/NativeScript
File: tns-core-modules/ui/core/view/view.android.ts (TypeScript)

Code before:
    }

    [elevationProperty.getDefault](): number {
        console.log("elevationProperty.getDefault");
        return undefined;
    }

    [elevationProperty.setNative](value: number) {
        if (sdkVersion() < 21) { return; }
        console.log("elevationProperty.setNative, value: " + value);
        const nativeView: any = this.nativeViewProtected;
        if (value !== undefined) {
            if (this._originalElevation === undefined) {
                this._originalElevation = nativeView.getElevation();
            }
            nativeView.setElevation(layout.toDevicePixels(value));
        } else {
            // reset to original value
            if (this._originalElevation !== undefined) {
                nativeView.setElevation(this._originalElevation);
            }
        }
        this._refreshStateListAnimator();
    }

    [androidPressedZProperty.getDefault](): number {
        console.log("androidPressedZProperty.getDefault");
        return undefined;
    }

    [androidPressedZProperty.setNative](value: number) {
        if (sdkVersion() < 21) { return; }
        console.log("androidPressedZProperty.setNative, value: " + value);
        this._refreshStateListAnimator();

    }

    _refreshStateListAnimator() {
        const nativeView: any = this.nativeViewProtected;
        // we have elevation or pressedZ
        if (this._originalStateListAnimator === undefined) {
            this._originalStateListAnimator = nativeView.getStateListAnimator();
        }
        const style = this.style;
        console.log("refreshing sla", this.elevation, this.androidPressedZ, this._originalStateListAnimator, elevationProperty.isSet(style), androidPressedZProperty.isSet(style));
        if ((!elevationProperty.isSet(style) && !androidPressedZProperty.isSet(style)) || // nothing to override
            (!androidPressedZProperty.isSet(style) && this._originalStateListAnimator === null)) { // we don't need pressedZ and there's no default
            // we have no reason to override anything, reset to default
            if (this._originalStateListAnimator !== nativeView.getStateListAnimator()) {
                nativeView.setStateListAnimator(this._originalStateListAnimator);
            }

Review comment (suggestion):
[Material design](https://material.io/design/environment/elevation.html#elevation-in-material-design) calls this dynamic elevation offset -- maybe rename ours to dynamicElevation or dynamicElevationOffset?

Also, you have added the android prefix to this property but not to `elevation` -- if dynamic elevation would be eventually supported for iOS as well, we can drop the prefix.

Code after:
        return this.nativeViewProtected.getAlpha();
    }
    [opacityProperty.setNative](value: number) {
        this.nativeViewProtected.setAlpha(float(value));
    }

    [androidElevationProperty.getDefault](): number {
        if (sdkVersion() < 21) {
            return 0;
        }

        // NOTE: overriden in Button implementation as for widgets with StateListAnimator (Button)
        // nativeView.getElevation() returns 0 at the time of the getDefault() query
        return layout.toDeviceIndependentPixels((<any>this.nativeViewProtected).getElevation());
    }
    [androidElevationProperty.setNative](value: number) {
        if (sdkVersion() < 21) {
            return;
        }

        this.refreshStateListAnimator();
    }

    [androidDynamicElevationOffsetProperty.getDefault](): number {
        return 0;
    }
    [androidDynamicElevationOffsetProperty.setNative](value: number) {
        if (sdkVersion() < 21) {
            return;
        }

        this.refreshStateListAnimator();
    }

    private refreshStateListAnimator() {
        const nativeView: any = this.nativeViewProtected;

        const ObjectAnimator = android.animation.ObjectAnimator;
        const AnimatorSet = android.animation.AnimatorSet;

        const duration = nativeView.getContext().getResources().getInteger(shortAnimTime) / 2;
        const elevation = layout.toDevicePixels(this.androidElevation || 0);
        const z = layout.toDevicePixels(0);
        const pressedZ = layout.toDevicePixels(this.androidDynamicElevationOffset || 0);

        const pressedSet = new AnimatorSet();
        pressedSet.playTogether(java.util.Arrays.asList([
            ObjectAnimator.ofFloat(nativeView, "translationZ", [pressedZ])
                .setDuration(duration),
            ObjectAnimator.ofFloat(nativeView, "elevation", [elevation])
                .setDuration(0),