mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-05 13:26:48 +08:00
fix: port boxshadow to background improvements
This commit is contained in:
@@ -4,7 +4,7 @@ import type { GestureTypes, GestureEventData } from '../../gestures';
|
||||
|
||||
// Types.
|
||||
import { ViewCommon, isEnabledProperty, originXProperty, originYProperty, isUserInteractionEnabledProperty } from './view-common';
|
||||
import { paddingLeftProperty, paddingTopProperty, paddingRightProperty, paddingBottomProperty } from '../../styling/style-properties';
|
||||
import { paddingLeftProperty, paddingTopProperty, paddingRightProperty, paddingBottomProperty, Length } from '../../styling/style-properties';
|
||||
import { layout } from '../../../utils';
|
||||
import { Trace } from '../../../trace';
|
||||
import { ShowModalOptions, hiddenProperty } from '../view-base';
|
||||
@@ -14,7 +14,7 @@ import { perspectiveProperty, visibilityProperty, opacityProperty, horizontalAli
|
||||
import { CoreTypes } from '../../../core-types';
|
||||
|
||||
import { Background, ad as androidBackground } from '../../styling/background';
|
||||
import { refreshBorderDrawable } from '../../styling/background.android';
|
||||
import { BackgroundClearFlags, refreshBorderDrawable } from '../../styling/background.android';
|
||||
import { profile } from '../../../profiling';
|
||||
import { topmost } from '../../frame/frame-stack';
|
||||
import { Screen } from '../../../platform';
|
||||
@@ -24,6 +24,7 @@ import lazy from '../../../utils/lazy';
|
||||
import { accessibilityEnabledProperty, accessibilityHiddenProperty, accessibilityHintProperty, accessibilityIdentifierProperty, accessibilityLabelProperty, accessibilityLanguageProperty, accessibilityLiveRegionProperty, accessibilityMediaSessionProperty, accessibilityRoleProperty, accessibilityStateProperty, accessibilityValueProperty } from '../../../accessibility/accessibility-properties';
|
||||
import { AccessibilityLiveRegion, AccessibilityRole, AndroidAccessibilityEvent, setupAccessibleView, isAccessibilityServiceEnabled, sendAccessibilityEvent, updateAccessibilityProperties, updateContentDescription, AccessibilityState } from '../../../accessibility';
|
||||
import * as Utils from '../../../utils';
|
||||
import { CSSShadow } from 'ui/styling/css-shadow';
|
||||
|
||||
export * from './view-common';
|
||||
// helpers (these are okay re-exported here)
|
||||
@@ -49,6 +50,10 @@ const modalMap = new Map<number, DialogOptions>();
|
||||
let TouchListener: TouchListener;
|
||||
let DialogFragment: DialogFragment;
|
||||
|
||||
interface AndroidView {
|
||||
_cachedDrawable: android.graphics.drawable.Drawable.ConstantState | android.graphics.drawable.Drawable;
|
||||
}
|
||||
|
||||
interface DialogOptions {
|
||||
owner: View;
|
||||
fullscreen: boolean;
|
||||
@@ -1114,6 +1119,19 @@ export class View extends ViewCommon {
|
||||
nativeView.setBackground(cachedDrawable);
|
||||
}
|
||||
}
|
||||
|
||||
protected _drawBoxShadow(boxShadow: CSSShadow) {
|
||||
const nativeView = this.nativeViewProtected;
|
||||
const config = {
|
||||
shadowColor: boxShadow.color.android,
|
||||
cornerRadius: Length.toDevicePixels(this.borderRadius as CoreTypes.LengthType, 0.0),
|
||||
spreadRadius: Length.toDevicePixels(boxShadow.spreadRadius, 0.0),
|
||||
blurRadius: Length.toDevicePixels(boxShadow.blurRadius, 0.0),
|
||||
offsetX: Length.toDevicePixels(boxShadow.offsetX, 0.0),
|
||||
offsetY: Length.toDevicePixels(boxShadow.offsetY, 0.0),
|
||||
};
|
||||
org.nativescript.widgets.Utils.drawBoxShadow(nativeView, JSON.stringify(config));
|
||||
}
|
||||
protected onBackgroundOrBorderPropertyChanged() {
|
||||
const nativeView = <android.view.View & { _cachedDrawable: android.graphics.drawable.Drawable.ConstantState | android.graphics.drawable.Drawable }>this.nativeViewProtected;
|
||||
if (!nativeView) {
|
||||
@@ -1121,11 +1139,36 @@ export class View extends ViewCommon {
|
||||
}
|
||||
|
||||
const background = this.style.backgroundInternal;
|
||||
|
||||
if (background.clearFlags & BackgroundClearFlags.CLEAR_BOX_SHADOW || background.clearFlags & BackgroundClearFlags.CLEAR_BACKGROUND_COLOR) {
|
||||
// clear background if we're clearing the box shadow
|
||||
// or the background has been removed
|
||||
nativeView.setBackground(null);
|
||||
}
|
||||
|
||||
const drawable = nativeView.getBackground();
|
||||
const androidView = (<any>this) as AndroidView;
|
||||
// use undefined as not set. getBackground will never return undefined only Drawable or null;
|
||||
if (androidView._cachedDrawable === undefined && drawable) {
|
||||
const constantState = drawable.getConstantState();
|
||||
androidView._cachedDrawable = constantState || drawable;
|
||||
}
|
||||
const isBorderDrawable = drawable instanceof org.nativescript.widgets.BorderDrawable;
|
||||
const onlyColor = !background.hasBorderWidth() && !background.hasBorderRadius() && !background.clipPath && !background.image && !!background.color;
|
||||
|
||||
// prettier-ignore
|
||||
const onlyColor = !background.hasBorderWidth()
|
||||
&& !background.hasBorderRadius()
|
||||
&& !background.hasBoxShadow()
|
||||
&& !background.clipPath
|
||||
&& !background.image
|
||||
&& !!background.color;
|
||||
|
||||
this._applyBackground(background, isBorderDrawable, onlyColor, drawable);
|
||||
|
||||
if (background.hasBoxShadow()) {
|
||||
this._drawBoxShadow(background.getBoxShadow());
|
||||
}
|
||||
|
||||
// TODO: Can we move BorderWidths as separate native setter?
|
||||
// This way we could skip setPadding if borderWidth is not changed.
|
||||
const leftPadding = Math.ceil(this.effectiveBorderLeftWidth + this.effectivePaddingLeft);
|
||||
@@ -1137,6 +1180,8 @@ export class View extends ViewCommon {
|
||||
} else {
|
||||
nativeView.setPadding(leftPadding, topPadding, rightPadding, bottomPadding);
|
||||
}
|
||||
// reset clear flags
|
||||
background.clearFlags = BackgroundClearFlags.NONE;
|
||||
}
|
||||
_redrawNativeBackground(value: android.graphics.drawable.Drawable | Background): void {
|
||||
if (value instanceof Background) {
|
||||
|
||||
@@ -1,139 +1,14 @@
|
||||
import { View } from '../core/view';
|
||||
import { LinearGradient } from './linear-gradient';
|
||||
import { CoreTypes } from '../../core-types';
|
||||
import { isDataURI, isFileOrResourcePath, layout, RESOURCE_PREFIX, FILE_PREFIX } from '../../utils';
|
||||
import { isDataURI, isFileOrResourcePath, RESOURCE_PREFIX, FILE_PREFIX } from '../../utils';
|
||||
import { parse } from '../../css-value';
|
||||
import { path, knownFolders } from '../../file-system';
|
||||
import * as application from '../../application';
|
||||
import { profile } from '../../profiling';
|
||||
import { CSSShadow } from './css-shadow';
|
||||
import { Length } from './style-properties';
|
||||
import { BackgroundClearFlags } from './background-common';
|
||||
export * from './background-common';
|
||||
|
||||
interface AndroidView {
|
||||
_cachedDrawable: android.graphics.drawable.Drawable.ConstantState | android.graphics.drawable.Drawable;
|
||||
}
|
||||
|
||||
// TODO: Change this implementation to use
|
||||
// We are using "ad" here to avoid namespace collision with the global android object
|
||||
export namespace ad {
|
||||
let SDK: number;
|
||||
function getSDK() {
|
||||
if (!SDK) {
|
||||
SDK = android.os.Build.VERSION.SDK_INT;
|
||||
}
|
||||
|
||||
return SDK;
|
||||
}
|
||||
|
||||
function isSetColorFilterOnlyWidget(nativeView: android.view.View): boolean {
|
||||
// prettier-ignore
|
||||
return (
|
||||
nativeView instanceof android.widget.Button
|
||||
|| (nativeView instanceof androidx.appcompat.widget.Toolbar && getSDK() >= 21)
|
||||
// There is an issue with the DrawableContainer which was fixed
|
||||
// for API version 21 and above: https://code.google.com/p/android/issues/detail?id=60183
|
||||
);
|
||||
}
|
||||
|
||||
export function onBackgroundOrBorderPropertyChanged(view: View) {
|
||||
const nativeView = <android.view.View>view.nativeViewProtected;
|
||||
if (!nativeView) {
|
||||
return;
|
||||
}
|
||||
|
||||
const background = view.style.backgroundInternal;
|
||||
|
||||
if (background.clearFlags & BackgroundClearFlags.CLEAR_BOX_SHADOW || background.clearFlags & BackgroundClearFlags.CLEAR_BACKGROUND_COLOR) {
|
||||
// clear background if we're clearing the box shadow
|
||||
// or the background has been removed
|
||||
nativeView.setBackground(null);
|
||||
}
|
||||
|
||||
let drawable = nativeView.getBackground();
|
||||
const androidView = (<any>view) as AndroidView;
|
||||
// use undefined as not set. getBackground will never return undefined only Drawable or null;
|
||||
if (androidView._cachedDrawable === undefined && drawable) {
|
||||
const constantState = drawable.getConstantState();
|
||||
androidView._cachedDrawable = constantState || drawable;
|
||||
}
|
||||
const isBorderDrawable = drawable instanceof org.nativescript.widgets.BorderDrawable;
|
||||
|
||||
// prettier-ignore
|
||||
const onlyColor = !background.hasBorderWidth()
|
||||
&& !background.hasBorderRadius()
|
||||
&& !background.hasBoxShadow()
|
||||
&& !background.clipPath
|
||||
&& !background.image
|
||||
&& !!background.color;
|
||||
|
||||
if (!isBorderDrawable && drawable instanceof android.graphics.drawable.ColorDrawable && onlyColor) {
|
||||
drawable.setColor(background.color.android);
|
||||
drawable.invalidateSelf();
|
||||
} else if (isSetColorFilterOnlyWidget(nativeView) && drawable && onlyColor) {
|
||||
if (isBorderDrawable && androidView._cachedDrawable) {
|
||||
if (!(androidView._cachedDrawable instanceof android.graphics.drawable.Drawable.ConstantState)) {
|
||||
return;
|
||||
}
|
||||
|
||||
drawable = androidView._cachedDrawable.newDrawable(nativeView.getResources());
|
||||
nativeView.setBackground(drawable);
|
||||
}
|
||||
|
||||
const backgroundColor = ((<any>drawable).backgroundColor = background.color.android);
|
||||
drawable.mutate();
|
||||
drawable.setColorFilter(backgroundColor, android.graphics.PorterDuff.Mode.SRC_IN);
|
||||
drawable.invalidateSelf(); // Make sure the drawable is invalidated. Android forgets to invalidate it in some cases: toolbar
|
||||
(<any>drawable).backgroundColor = backgroundColor;
|
||||
} else if (!isBorderDrawable && onlyColor) {
|
||||
// this is the fastest way to change only background color
|
||||
nativeView.setBackgroundColor(background.color.android);
|
||||
} else if (!background.isEmpty()) {
|
||||
let backgroundDrawable = drawable;
|
||||
|
||||
if (drawable instanceof org.nativescript.widgets.BoxShadowDrawable) {
|
||||
// if we have BoxShadow's we have to get the underlying drawable
|
||||
backgroundDrawable = drawable.getWrappedDrawable();
|
||||
}
|
||||
|
||||
if (backgroundDrawable instanceof org.nativescript.widgets.BorderDrawable) {
|
||||
refreshBorderDrawable(view, backgroundDrawable);
|
||||
} else {
|
||||
backgroundDrawable = new org.nativescript.widgets.BorderDrawable(layout.getDisplayDensity(), view.toString());
|
||||
refreshBorderDrawable(view, <org.nativescript.widgets.BorderDrawable>backgroundDrawable);
|
||||
nativeView.setBackground(backgroundDrawable);
|
||||
}
|
||||
} else {
|
||||
const cachedDrawable = androidView._cachedDrawable;
|
||||
let defaultDrawable: android.graphics.drawable.Drawable = null;
|
||||
if (cachedDrawable) {
|
||||
if (cachedDrawable instanceof android.graphics.drawable.Drawable.ConstantState) {
|
||||
defaultDrawable = cachedDrawable.newDrawable(nativeView.getResources());
|
||||
} else if (cachedDrawable instanceof android.graphics.drawable.Drawable) {
|
||||
defaultDrawable = cachedDrawable;
|
||||
}
|
||||
}
|
||||
|
||||
nativeView.setBackground(defaultDrawable);
|
||||
}
|
||||
|
||||
if (background.hasBoxShadow()) {
|
||||
drawBoxShadow(nativeView, view, background.getBoxShadow());
|
||||
}
|
||||
|
||||
// TODO: Can we move BorderWidths as separate native setter?
|
||||
// This way we could skip setPadding if borderWidth is not changed.
|
||||
const leftPadding = Math.ceil(view.effectiveBorderLeftWidth + view.effectivePaddingLeft);
|
||||
const topPadding = Math.ceil(view.effectiveBorderTopWidth + view.effectivePaddingTop);
|
||||
const rightPadding = Math.ceil(view.effectiveBorderRightWidth + view.effectivePaddingRight);
|
||||
const bottomPadding = Math.ceil(view.effectiveBorderBottomWidth + view.effectivePaddingBottom);
|
||||
|
||||
nativeView.setPadding(leftPadding, topPadding, rightPadding, bottomPadding);
|
||||
|
||||
// reset clear flags
|
||||
background.clearFlags = BackgroundClearFlags.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
function fromBase64(source: string): android.graphics.Bitmap {
|
||||
@@ -253,18 +128,6 @@ function createNativeCSSValueArray(css: string): androidNative.Array<org.natives
|
||||
return nativeArray;
|
||||
}
|
||||
|
||||
function drawBoxShadow(nativeView: android.view.View, view: View, boxShadow: CSSShadow) {
|
||||
const config = {
|
||||
shadowColor: boxShadow.color.android,
|
||||
cornerRadius: Length.toDevicePixels(view.borderRadius as CoreTypes.LengthType, 0.0),
|
||||
spreadRadius: Length.toDevicePixels(boxShadow.spreadRadius, 0.0),
|
||||
blurRadius: Length.toDevicePixels(boxShadow.blurRadius, 0.0),
|
||||
offsetX: Length.toDevicePixels(boxShadow.offsetX, 0.0),
|
||||
offsetY: Length.toDevicePixels(boxShadow.offsetY, 0.0),
|
||||
};
|
||||
org.nativescript.widgets.Utils.drawBoxShadow(nativeView, JSON.stringify(config));
|
||||
}
|
||||
|
||||
export enum CacheMode {
|
||||
none,
|
||||
memory,
|
||||
|
||||
Reference in New Issue
Block a user