From 16563b64ee223c4361007bba34621b7155b3af99 Mon Sep 17 00:00:00 2001 From: farfromrefuge Date: Fri, 1 Oct 2021 14:58:59 +0200 Subject: [PATCH 1/2] feat: improved background handling (#9548) * fix: refactor background handling. The idea is for views to handle sepecial case themselves. I realised that android.widget.Button was materialized even if you were not using it because there was a test for instanceof in the background handling. Now the special background handling is done in Button and ActionBar * fix: automated tests are now passing * fix: removed duplicated line * fix: port boxshadow to background improvements * Update packages/core/ui/core/view/index.android.ts Co-authored-by: Igor Randjelovic * Update packages/core/ui/action-bar/index.android.ts Co-authored-by: Igor Randjelovic * chore: remove empty namespace Co-authored-by: Igor Randjelovic --- packages/core/ui/action-bar/index.android.ts | 33 +++- packages/core/ui/button/index.android.ts | 27 ++++ packages/core/ui/core/view/index.android.ts | 113 ++++++++++++-- packages/core/ui/core/view/index.d.ts | 6 + packages/core/ui/core/view/view-common.ts | 3 + .../core/ui/styling/background.android.ts | 146 +----------------- 6 files changed, 171 insertions(+), 157 deletions(-) diff --git a/packages/core/ui/action-bar/index.android.ts b/packages/core/ui/action-bar/index.android.ts index 137871df50..0a1bcdd15f 100644 --- a/packages/core/ui/action-bar/index.android.ts +++ b/packages/core/ui/action-bar/index.android.ts @@ -7,6 +7,9 @@ import { colorProperty } from '../styling/style-properties'; import { ImageSource } from '../../image-source'; import * as application from '../../application'; import { isAccessibilityServiceEnabled, updateContentDescription } from '../../accessibility'; +import type { Background } from '../styling/background'; +import { Device } from '../../platform'; +import lazy from '../../utils/lazy'; export * from './action-bar-common'; @@ -14,6 +17,8 @@ const R_ID_HOME = 0x0102002c; const ACTION_ITEM_ID_OFFSET = 10000; const DEFAULT_ELEVATION = 4; +const sdkVersion = lazy(() => parseInt(Device.sdkVersion)); + let AppCompatTextView; let actionItemIdGenerator = ACTION_ITEM_ID_OFFSET; function generateItemId(): number { @@ -59,7 +64,7 @@ function initializeMenuItemClickListener(): void { return; } - apiLevel = android.os.Build.VERSION.SDK_INT; + apiLevel = sdkVersion(); AppCompatTextView = androidx.appcompat.widget.AppCompatTextView; @@ -216,6 +221,32 @@ export class ActionBar extends ActionBarBase { this._updateNavigationButton(); } + public _applyBackground(background: Background, isBorderDrawable, onlyColor: boolean, backgroundDrawable: any) { + const nativeView = this.nativeViewProtected; + if (backgroundDrawable && onlyColor && sdkVersion() >= 21) { + if (isBorderDrawable && (nativeView)._cachedDrawable) { + backgroundDrawable = (nativeView)._cachedDrawable; + // we need to duplicate the drawable or we lose the "default" cached drawable + const constantState = backgroundDrawable.getConstantState(); + if (constantState) { + try { + backgroundDrawable = constantState.newDrawable(nativeView.getResources()); + // eslint-disable-next-line no-empty + } catch {} + } + nativeView.setBackground(backgroundDrawable); + } + + const backgroundColor = ((backgroundDrawable).backgroundColor = background.color.android); + backgroundDrawable.mutate(); + backgroundDrawable.setColorFilter(backgroundColor, android.graphics.PorterDuff.Mode.SRC_IN); + backgroundDrawable.invalidateSelf(); // Make sure the drawable is invalidated. Android forgets to invalidate it in some cases: toolbar + (backgroundDrawable).backgroundColor = backgroundColor; + } else { + super._applyBackground(background, isBorderDrawable, onlyColor, backgroundDrawable); + } + } + public _onAndroidItemSelected(itemId: number): boolean { // Handle home button if (this.navigationButton && itemId === R_ID_HOME) { diff --git a/packages/core/ui/button/index.android.ts b/packages/core/ui/button/index.android.ts index 3dbdb738f0..66c6446670 100644 --- a/packages/core/ui/button/index.android.ts +++ b/packages/core/ui/button/index.android.ts @@ -7,6 +7,7 @@ import { profile } from '../../profiling'; import { TouchGestureEventData, GestureTypes, TouchAction } from '../gestures'; import { Device } from '../../platform'; import lazy from '../../utils/lazy'; +import type { Background } from 'ui/styling/background'; export * from './button-common'; @@ -58,6 +59,32 @@ export class Button extends ButtonBase { private _stateListAnimator: any; private _highlightedHandler: (args: TouchGestureEventData) => void; + public _applyBackground(background: Background, isBorderDrawable, onlyColor: boolean, backgroundDrawable: any) { + const nativeView = this.nativeViewProtected; + if (backgroundDrawable && onlyColor) { + if (isBorderDrawable && (nativeView)._cachedDrawable) { + backgroundDrawable = (nativeView)._cachedDrawable; + // we need to duplicate the drawable or we lose the "default" cached drawable + const constantState = backgroundDrawable.getConstantState(); + if (constantState) { + try { + backgroundDrawable = constantState.newDrawable(nativeView.getResources()); + // eslint-disable-next-line no-empty + } catch {} + } + nativeView.setBackground(backgroundDrawable); + } + + const backgroundColor = ((backgroundDrawable).backgroundColor = background.color.android); + backgroundDrawable.mutate(); + backgroundDrawable.setColorFilter(backgroundColor, android.graphics.PorterDuff.Mode.SRC_IN); + backgroundDrawable.invalidateSelf(); // Make sure the drawable is invalidated. Android forgets to invalidate it in some cases: toolbar + (backgroundDrawable).backgroundColor = backgroundColor; + } else { + super._applyBackground(background, isBorderDrawable, onlyColor, backgroundDrawable); + } + } + @profile public createNativeView() { if (!AndroidButton) { diff --git a/packages/core/ui/core/view/index.android.ts b/packages/core/ui/core/view/index.android.ts index 15f4645808..72a41c0562 100644 --- a/packages/core/ui/core/view/index.android.ts +++ b/packages/core/ui/core/view/index.android.ts @@ -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,6 +14,7 @@ import { perspectiveProperty, visibilityProperty, opacityProperty, horizontalAli import { CoreTypes } from '../../../core-types'; import { Background, ad as androidBackground } from '../../styling/background'; +import { BackgroundClearFlags, refreshBorderDrawable } from '../../styling/background.android'; import { profile } from '../../../profiling'; import { topmost } from '../../frame/frame-stack'; import { Screen } from '../../../platform'; @@ -23,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 '../../styling/css-shadow'; export * from './view-common'; // helpers (these are okay re-exported here) @@ -56,6 +58,10 @@ const modalMap = new Map(); let TouchListener: TouchListener; let DialogFragment: DialogFragment; +interface AndroidView { + _cachedDrawable: android.graphics.drawable.Drawable.ConstantState | android.graphics.drawable.Drawable; +} + interface DialogOptions { owner: View; fullscreen: boolean; @@ -1065,21 +1071,19 @@ export class View extends ViewCommon { [backgroundInternalProperty.getDefault](): android.graphics.drawable.Drawable { const nativeView = this.nativeViewProtected; - const drawable = nativeView.getBackground(); + let drawable = nativeView.getBackground(); if (drawable) { const constantState = drawable.getConstantState(); if (constantState) { try { - return constantState.newDrawable(nativeView.getResources()); - } catch (e) { - return drawable; - } - } else { - return drawable; + drawable = constantState.newDrawable(nativeView.getResources()); + // eslint-disable-next-line no-empty + } catch {} } } + (nativeView)._cachedDrawable = drawable; - return null; + return drawable; } [backgroundInternalProperty.setNative](value: android.graphics.drawable.Drawable | Background) { this._redrawNativeBackground(value); @@ -1101,9 +1105,96 @@ export class View extends ViewCommon { } } + public _applyBackground(background: Background, isBorderDrawable: boolean, onlyColor: boolean, backgroundDrawable: any) { + const nativeView = this.nativeViewProtected; + if (!isBorderDrawable && onlyColor) { + if (backgroundDrawable && backgroundDrawable.setColor) { + backgroundDrawable.setColor(background.color.android); + backgroundDrawable.invalidateSelf(); + } else { + nativeView.setBackgroundColor(background.color.android); + } + } else if (!background.isEmpty()) { + if (!isBorderDrawable) { + backgroundDrawable = new org.nativescript.widgets.BorderDrawable(layout.getDisplayDensity(), this.toString()); + refreshBorderDrawable(this, backgroundDrawable); + nativeView.setBackground(backgroundDrawable); + } else { + refreshBorderDrawable(this, backgroundDrawable); + } + } else { + //empty background let s reset + const cachedDrawable = (nativeView)._cachedDrawable; + 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 = this.nativeViewProtected; + if (!nativeView) { + return; + } + + 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 = (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; + + // 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); + const topPadding = Math.ceil(this.effectiveBorderTopWidth + this.effectivePaddingTop); + const rightPadding = Math.ceil(this.effectiveBorderRightWidth + this.effectivePaddingRight); + const bottomPadding = Math.ceil(this.effectiveBorderBottomWidth + this.effectivePaddingBottom); + if (this._isPaddingRelative) { + nativeView.setPaddingRelative(leftPadding, topPadding, rightPadding, bottomPadding); + } 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) { - androidBackground.onBackgroundOrBorderPropertyChanged(this); + this.onBackgroundOrBorderPropertyChanged(); } else { const nativeView = this.nativeViewProtected; nativeView.setBackground(value); @@ -1119,8 +1210,6 @@ export class View extends ViewCommon { } else { nativeView.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom); } - - (nativeView).background = undefined; } } diff --git a/packages/core/ui/core/view/index.d.ts b/packages/core/ui/core/view/index.d.ts index f4d6a24457..81cbe62d73 100644 --- a/packages/core/ui/core/view/index.d.ts +++ b/packages/core/ui/core/view/index.d.ts @@ -828,6 +828,12 @@ export abstract class View extends ViewBase { * @private */ _redrawNativeBackground(value: any): void; + /** + * @private + * method called on Android to apply the background. This allows custom handling + */ + _applyBackground(background: Background, isBorderDrawable: boolean, onlyColor: boolean, backgroundDrawable: any); + /** * @private */ diff --git a/packages/core/ui/core/view/view-common.ts b/packages/core/ui/core/view/view-common.ts index 2b2ff610d4..4990823a50 100644 --- a/packages/core/ui/core/view/view-common.ts +++ b/packages/core/ui/core/view/view-common.ts @@ -1067,6 +1067,9 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition { public _redrawNativeBackground(value: any): void { // } + public _applyBackground(background, isBorderDrawable: boolean, onlyColor: boolean, backgroundDrawable: any) { + // + } _onAttachedToWindow(): void { // diff --git a/packages/core/ui/styling/background.android.ts b/packages/core/ui/styling/background.android.ts index 5449a52556..29542c3872 100644 --- a/packages/core/ui/styling/background.android.ts +++ b/packages/core/ui/styling/background.android.ts @@ -1,141 +1,11 @@ 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 = 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 = (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 = ((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 - (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, 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 { const bytes = android.util.Base64.decode(source, android.util.Base64.DEFAULT); @@ -164,7 +34,7 @@ function fromGradient(gradient: LinearGradient): org.nativescript.widgets.Linear } const pattern = /url\(('|")(.*?)\1\)/; -function refreshBorderDrawable(this: void, view: View, borderDrawable: org.nativescript.widgets.BorderDrawable) { +export function refreshBorderDrawable(this: void, view: View, borderDrawable: org.nativescript.widgets.BorderDrawable) { const nativeView = view.nativeViewProtected; const context = nativeView.getContext(); @@ -253,18 +123,6 @@ function createNativeCSSValueArray(css: string): androidNative.Array Date: Fri, 1 Oct 2021 15:13:15 +0200 Subject: [PATCH 2/2] chore: cleanup --- packages/core/ui/core/view/index.android.ts | 54 ++++++++++++--------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/packages/core/ui/core/view/index.android.ts b/packages/core/ui/core/view/index.android.ts index 72a41c0562..6f1cb6f46a 100644 --- a/packages/core/ui/core/view/index.android.ts +++ b/packages/core/ui/core/view/index.android.ts @@ -1109,21 +1109,23 @@ export class View extends ViewCommon { const nativeView = this.nativeViewProtected; if (!isBorderDrawable && onlyColor) { if (backgroundDrawable && backgroundDrawable.setColor) { + // android.graphics.drawable.ColorDrawable backgroundDrawable.setColor(background.color.android); backgroundDrawable.invalidateSelf(); } else { nativeView.setBackgroundColor(background.color.android); } } else if (!background.isEmpty()) { - if (!isBorderDrawable) { - backgroundDrawable = new org.nativescript.widgets.BorderDrawable(layout.getDisplayDensity(), this.toString()); + if (isBorderDrawable) { + // org.nativescript.widgets.BorderDrawable refreshBorderDrawable(this, backgroundDrawable); - nativeView.setBackground(backgroundDrawable); } else { + backgroundDrawable = new org.nativescript.widgets.BorderDrawable(layout.getDisplayDensity(), this.toString()); refreshBorderDrawable(this, backgroundDrawable); + nativeView.setBackground(backgroundDrawable); } } else { - //empty background let s reset + //empty background let's reset const cachedDrawable = (nativeView)._cachedDrawable; nativeView.setBackground(cachedDrawable); } @@ -1141,6 +1143,28 @@ export class View extends ViewCommon { }; org.nativescript.widgets.Utils.drawBoxShadow(nativeView, JSON.stringify(config)); } + + _redrawNativeBackground(value: android.graphics.drawable.Drawable | Background): void { + if (value instanceof Background) { + this.onBackgroundOrBorderPropertyChanged(); + } else { + const nativeView = this.nativeViewProtected; + nativeView.setBackground(value); + + const style = this.style; + const paddingTop = paddingTopProperty.isSet(style) ? this.effectivePaddingTop : this._defaultPaddingTop; + const paddingRight = paddingRightProperty.isSet(style) ? this.effectivePaddingRight : this._defaultPaddingRight; + const paddingBottom = paddingBottomProperty.isSet(style) ? this.effectivePaddingBottom : this._defaultPaddingBottom; + const paddingLeft = paddingLeftProperty.isSet(style) ? this.effectivePaddingLeft : this._defaultPaddingLeft; + + if (this._isPaddingRelative) { + nativeView.setPaddingRelative(paddingLeft, paddingTop, paddingRight, paddingBottom); + } else { + nativeView.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom); + } + } + } + protected onBackgroundOrBorderPropertyChanged() { const nativeView = this.nativeViewProtected; if (!nativeView) { @@ -1184,34 +1208,16 @@ export class View extends ViewCommon { const topPadding = Math.ceil(this.effectiveBorderTopWidth + this.effectivePaddingTop); const rightPadding = Math.ceil(this.effectiveBorderRightWidth + this.effectivePaddingRight); const bottomPadding = Math.ceil(this.effectiveBorderBottomWidth + this.effectivePaddingBottom); + if (this._isPaddingRelative) { nativeView.setPaddingRelative(leftPadding, topPadding, rightPadding, bottomPadding); } 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) { - this.onBackgroundOrBorderPropertyChanged(); - } else { - const nativeView = this.nativeViewProtected; - nativeView.setBackground(value); - - const style = this.style; - const paddingTop = paddingTopProperty.isSet(style) ? this.effectivePaddingTop : this._defaultPaddingTop; - const paddingRight = paddingRightProperty.isSet(style) ? this.effectivePaddingRight : this._defaultPaddingRight; - const paddingBottom = paddingBottomProperty.isSet(style) ? this.effectivePaddingBottom : this._defaultPaddingBottom; - const paddingLeft = paddingLeftProperty.isSet(style) ? this.effectivePaddingLeft : this._defaultPaddingLeft; - - if (this._isPaddingRelative) { - nativeView.setPaddingRelative(paddingLeft, paddingTop, paddingRight, paddingBottom); - } else { - nativeView.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom); - } - } - } public accessibilityAnnouncement(message = this.accessibilityLabel): void { this.sendAccessibilityEvent({