mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-15 19:26:42 +08:00
backgroundImage property now use Fetcher & Cache as Image component (#4030)
* backgroundImage property now use Fetcher & Cache as Image component Fix GridLayout tests on iPhone Plus - actualLength wasn’t rounded ImageCache is closed when activity is stopped * Fix reset of background drawable. * additional check for drawable * imageCache init cache on activity Started
This commit is contained in:
@ -63,5 +63,5 @@ function reset(page: Page) {
|
||||
page.css = "";
|
||||
page.actionBarHidden = false;
|
||||
page.backgroundSpanUnderStatusBar = false;
|
||||
page.actionBar.style.backgroundColor = unsetValue;
|
||||
page.actionBar.backgroundColor = unsetValue;
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ import * as platformTests from "./platform/platform-tests";
|
||||
allTests["PLATFORM"] = platformTests;
|
||||
|
||||
import * as fsTests from "./file-system/file-system-tests";
|
||||
allTests["FILE SYSTEM"] = fsTests;
|
||||
allTests["FILE-SYSTEM"] = fsTests;
|
||||
|
||||
import * as httpTests from "./http/http-tests";
|
||||
allTests["HTTP"] = httpTests;
|
||||
@ -47,13 +47,13 @@ import * as fetchTests from "./fetch/fetch-tests";
|
||||
allTests["FETCH"] = fetchTests;
|
||||
|
||||
import * as appSettingsTests from "./application-settings/application-settings-tests";
|
||||
allTests["APPLICATION SETTINGS"] = appSettingsTests;
|
||||
allTests["APPLICATION-SETTINGS"] = appSettingsTests;
|
||||
|
||||
import * as applicationTests from "./application/application-tests";
|
||||
allTests["APPLICATION"] = applicationTests;
|
||||
|
||||
import * as imageSourceTests from "./image-source/image-source-tests";
|
||||
allTests["IMAGE SOURCE"] = imageSourceTests;
|
||||
allTests["IMAGE-SOURCE"] = imageSourceTests;
|
||||
|
||||
import * as observableArrayTests from "./data/observable-array-tests";
|
||||
allTests["OBSERVABLE-ARRAY"] = observableArrayTests;
|
||||
|
@ -17,12 +17,12 @@ import * as ViewModule from "tns-core-modules/ui/core/view";
|
||||
import * as helper from "../helper";
|
||||
import * as ObservableModule from "tns-core-modules/data/observable";
|
||||
import * as color from "tns-core-modules/color";
|
||||
|
||||
import * as backgroundModule from "tns-core-modules/ui/styling/background";
|
||||
import { android as androidApp } from "tns-core-modules/application";
|
||||
const imagePath = "~/logo.png";
|
||||
|
||||
if (isAndroid) {
|
||||
const imageModule = require("ui/image");
|
||||
imageModule.currentMode = imageModule.CacheMode.memory; // use memory cache only.
|
||||
(<any>backgroundModule).initImageCache(androidApp.startActivity, (<any>backgroundModule).CacheMode.memory); // use memory cache only.
|
||||
}
|
||||
|
||||
export const test_Image_Members = function () {
|
||||
|
@ -248,7 +248,7 @@ function initComponentCallbacks() {
|
||||
},
|
||||
|
||||
onConfigurationChanged: function (newConfig: android.content.res.Configuration) {
|
||||
let newOrientation = newConfig.orientation;
|
||||
const newOrientation = newConfig.orientation;
|
||||
if (newOrientation === currentOrientation) {
|
||||
return;
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ function getApplication() {
|
||||
|
||||
return application;
|
||||
}
|
||||
|
||||
function getResources() {
|
||||
if (!resources) {
|
||||
resources = getApplication().getResources();
|
||||
@ -248,7 +249,7 @@ export function fromUrl(url: string): Promise<ImageSource> {
|
||||
|
||||
export function fromFileOrResource(path: string): ImageSource {
|
||||
if (!isFileOrResourcePath(path)) {
|
||||
throw new Error("Path \"" + "\" is not a valid file or resource.");
|
||||
throw new Error(`${path} is not a valid file or resource.`);
|
||||
}
|
||||
|
||||
if (path.indexOf(RESOURCE_PREFIX) === 0) {
|
||||
|
@ -403,9 +403,12 @@ export class View extends ViewCommon {
|
||||
if (value instanceof UIColor) {
|
||||
this.nativeView.backgroundColor = value;
|
||||
} else {
|
||||
this.nativeView.backgroundColor = ios.createBackgroundUIColor(this);
|
||||
ios.createBackgroundUIColor(this, (color: UIColor) => {
|
||||
this.nativeView.backgroundColor = color;
|
||||
});
|
||||
this._setNativeClipToBounds();
|
||||
}
|
||||
|
||||
if (!updateSuspended) {
|
||||
CATransaction.commit();
|
||||
}
|
||||
|
@ -9,44 +9,6 @@ export * from "./image-common";
|
||||
const FILE_PREFIX = "file:///";
|
||||
const ASYNC = "async";
|
||||
|
||||
let imageFetcher: org.nativescript.widgets.image.Fetcher;
|
||||
let imageCache: org.nativescript.widgets.image.Cache;
|
||||
|
||||
export enum CacheMode {
|
||||
none,
|
||||
memory,
|
||||
diskAndMemory
|
||||
}
|
||||
|
||||
export let currentCacheMode: CacheMode;
|
||||
|
||||
export function initImageCache(context: android.content.Context, mode = CacheMode.diskAndMemory, memoryCacheSize: number = 0.25, diskCacheSize: number = 10 * 1024 * 1024): void {
|
||||
if (currentCacheMode === mode) {
|
||||
return;
|
||||
}
|
||||
|
||||
currentCacheMode = mode;
|
||||
if (!imageFetcher) {
|
||||
imageFetcher = org.nativescript.widgets.image.Fetcher.getInstance(context);
|
||||
}
|
||||
|
||||
// Disable cache.
|
||||
if (mode === CacheMode.none) {
|
||||
if (imageCache != null && imageFetcher != null) {
|
||||
imageFetcher.clearCache();
|
||||
}
|
||||
}
|
||||
|
||||
let params = new org.nativescript.widgets.image.Cache.CacheParams();
|
||||
params.memoryCacheEnabled = mode !== CacheMode.none;
|
||||
params.setMemCacheSizePercent(memoryCacheSize); // Set memory cache to % of app memory
|
||||
params.diskCacheEnabled = mode === CacheMode.diskAndMemory;
|
||||
params.diskCacheSize = diskCacheSize;
|
||||
imageCache = org.nativescript.widgets.image.Cache.getInstance(params);
|
||||
imageFetcher.addImageCache(imageCache);
|
||||
imageFetcher.initCache();
|
||||
}
|
||||
|
||||
interface ImageLoadedListener {
|
||||
new (owner: Image): org.nativescript.widgets.image.Worker.OnImageLoadedListener;
|
||||
}
|
||||
@ -84,9 +46,6 @@ export class Image extends ImageBase {
|
||||
|
||||
public createNativeView() {
|
||||
initializeImageLoadedListener();
|
||||
if (!imageFetcher) {
|
||||
initImageCache(this._context);
|
||||
}
|
||||
|
||||
const imageView = new org.nativescript.widgets.ImageView(this._context);
|
||||
const listener = new ImageLoadedListener(this);
|
||||
@ -124,12 +83,10 @@ export class Image extends ImageBase {
|
||||
if (isDataURI(value)) {
|
||||
// TODO: Check with runtime what should we do in case of base64 string.
|
||||
super._createImageSourceFromSrc();
|
||||
}
|
||||
else if (isFileOrResourcePath(value)) {
|
||||
} else if (isFileOrResourcePath(value)) {
|
||||
if (value.indexOf(RESOURCE_PREFIX) === 0) {
|
||||
imageView.setUri(value, this.decodeWidth, this.decodeHeight, this.useCache, async);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
let fileName = value;
|
||||
if (fileName.indexOf("~/") === 0) {
|
||||
fileName = path.join(knownFolders.currentApp().path, fileName.replace("~/", ""));
|
||||
@ -137,8 +94,7 @@ export class Image extends ImageBase {
|
||||
|
||||
imageView.setUri(FILE_PREFIX + fileName, this.decodeWidth, this.decodeHeight, this.useCache, async);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// For backwards compatibility http always use async loading.
|
||||
imageView.setUri(value, this.decodeWidth, this.decodeHeight, this.useCache, true);
|
||||
}
|
||||
|
@ -100,12 +100,13 @@ export class Label extends TextBase implements LabelDefinition {
|
||||
}
|
||||
[backgroundInternalProperty.setNative](value: Background) {
|
||||
if (value instanceof Background) {
|
||||
const uiColor = <UIColor>ios.createBackgroundUIColor(this, true);
|
||||
value = uiColor ? uiColor.CGColor : null;
|
||||
ios.createBackgroundUIColor(this, (color: UIColor) => {
|
||||
const cgColor = color ? color.CGColor : null;
|
||||
this.nativeView.layer.backgroundColor = cgColor;
|
||||
}, true);
|
||||
}
|
||||
|
||||
this._setNativeClipToBounds();
|
||||
this.nativeView.layer.backgroundColor = value;
|
||||
}
|
||||
|
||||
[borderTopWidthProperty.setNative](value: Length) {
|
||||
|
@ -174,7 +174,7 @@ export class GridLayout extends GridLayoutBase {
|
||||
|
||||
actualLength = offset - roundedOffset;
|
||||
roundedLength = Math.round(actualLength);
|
||||
columnGroup.rowOrColumn._actualLength = layout.toDeviceIndependentPixels(roundedLength);
|
||||
columnGroup.rowOrColumn._actualLength = layout.round(layout.toDeviceIndependentPixels(roundedLength));
|
||||
roundedOffset += roundedLength;
|
||||
|
||||
this.columnOffsets.push(roundedOffset);
|
||||
@ -191,7 +191,7 @@ export class GridLayout extends GridLayoutBase {
|
||||
|
||||
actualLength = offset - roundedOffset;
|
||||
roundedLength = Math.round(actualLength);
|
||||
rowGroup.rowOrColumn._actualLength = layout.toDeviceIndependentPixels(roundedLength);
|
||||
rowGroup.rowOrColumn._actualLength = layout.round(layout.toDeviceIndependentPixels(roundedLength));
|
||||
roundedOffset += roundedLength;
|
||||
|
||||
this.rowOffsets.push(roundedOffset);
|
||||
|
@ -94,7 +94,6 @@ export class Page extends PageBase {
|
||||
const layout = new org.nativescript.widgets.GridLayout(this._context);
|
||||
layout.addRow(new org.nativescript.widgets.ItemSpec(1, org.nativescript.widgets.GridUnitType.auto));
|
||||
layout.addRow(new org.nativescript.widgets.ItemSpec(1, org.nativescript.widgets.GridUnitType.star));
|
||||
layout.setBackgroundColor(-1);
|
||||
return layout;
|
||||
}
|
||||
|
||||
|
@ -1,17 +1,15 @@
|
||||
// Deifinitions.
|
||||
import { Background as BackgroundDefinition, BackgroundDrawParams } from "./background";
|
||||
import { Background as BackgroundDefinition } from "./background";
|
||||
import { BackgroundRepeat } from "../core/view";
|
||||
import { ImageSource } from "../../image-source";
|
||||
|
||||
// Types.
|
||||
import { Color } from "../../color";
|
||||
import { CSSValue, parse as cssParse } from "../../css-value";
|
||||
|
||||
export class Background implements BackgroundDefinition {
|
||||
public static default = new Background();
|
||||
|
||||
public color: Color;
|
||||
public image: ImageSource;
|
||||
public image: string;
|
||||
public repeat: BackgroundRepeat;
|
||||
public position: string;
|
||||
public size: string;
|
||||
@ -30,7 +28,7 @@ export class Background implements BackgroundDefinition {
|
||||
public clipPath: string;
|
||||
|
||||
private clone(): Background {
|
||||
let clone = new Background();
|
||||
const clone = new Background();
|
||||
|
||||
clone.color = this.color;
|
||||
clone.image = this.image;
|
||||
@ -55,269 +53,113 @@ export class Background implements BackgroundDefinition {
|
||||
}
|
||||
|
||||
public withColor(value: Color): Background {
|
||||
let clone = this.clone();
|
||||
const clone = this.clone();
|
||||
clone.color = value;
|
||||
return clone;
|
||||
}
|
||||
|
||||
public withImage(value: ImageSource): Background {
|
||||
let clone = this.clone();
|
||||
public withImage(value: string): Background {
|
||||
const clone = this.clone();
|
||||
clone.image = value;
|
||||
return clone;
|
||||
}
|
||||
|
||||
public withRepeat(value: BackgroundRepeat): Background {
|
||||
let clone = this.clone();
|
||||
const clone = this.clone();
|
||||
clone.repeat = value;
|
||||
return clone;
|
||||
}
|
||||
|
||||
public withPosition(value: string): Background {
|
||||
let clone = this.clone();
|
||||
const clone = this.clone();
|
||||
clone.position = value;
|
||||
return clone;
|
||||
}
|
||||
|
||||
public withSize(value: string): Background {
|
||||
let clone = this.clone();
|
||||
const clone = this.clone();
|
||||
clone.size = value;
|
||||
return clone;
|
||||
}
|
||||
|
||||
public withBorderTopColor(value: Color): Background {
|
||||
let clone = this.clone();
|
||||
const clone = this.clone();
|
||||
clone.borderTopColor = value;
|
||||
return clone;
|
||||
}
|
||||
|
||||
public withBorderRightColor(value: Color): Background {
|
||||
let clone = this.clone();
|
||||
const clone = this.clone();
|
||||
clone.borderRightColor = value;
|
||||
return clone;
|
||||
}
|
||||
|
||||
public withBorderBottomColor(value: Color): Background {
|
||||
let clone = this.clone();
|
||||
const clone = this.clone();
|
||||
clone.borderBottomColor = value;
|
||||
return clone;
|
||||
}
|
||||
|
||||
public withBorderLeftColor(value: Color): Background {
|
||||
let clone = this.clone();
|
||||
const clone = this.clone();
|
||||
clone.borderLeftColor = value;
|
||||
return clone;
|
||||
}
|
||||
|
||||
public withBorderTopWidth(value: number): Background {
|
||||
let clone = this.clone();
|
||||
const clone = this.clone();
|
||||
clone.borderTopWidth = value;
|
||||
return clone;
|
||||
}
|
||||
|
||||
public withBorderRightWidth(value: number): Background {
|
||||
let clone = this.clone();
|
||||
const clone = this.clone();
|
||||
clone.borderRightWidth = value;
|
||||
return clone;
|
||||
}
|
||||
|
||||
public withBorderBottomWidth(value: number): Background {
|
||||
let clone = this.clone();
|
||||
const clone = this.clone();
|
||||
clone.borderBottomWidth = value;
|
||||
return clone;
|
||||
}
|
||||
|
||||
public withBorderLeftWidth(value: number): Background {
|
||||
let clone = this.clone();
|
||||
const clone = this.clone();
|
||||
clone.borderLeftWidth = value;
|
||||
return clone;
|
||||
}
|
||||
|
||||
public withBorderTopLeftRadius(value: number): Background {
|
||||
let clone = this.clone();
|
||||
const clone = this.clone();
|
||||
clone.borderTopLeftRadius = value;
|
||||
return clone;
|
||||
}
|
||||
|
||||
public withBorderTopRightRadius(value: number): Background {
|
||||
let clone = this.clone();
|
||||
const clone = this.clone();
|
||||
clone.borderTopRightRadius = value;
|
||||
return clone;
|
||||
}
|
||||
|
||||
public withBorderBottomRightRadius(value: number): Background {
|
||||
let clone = this.clone();
|
||||
const clone = this.clone();
|
||||
clone.borderBottomRightRadius = value;
|
||||
return clone;
|
||||
}
|
||||
|
||||
public withBorderBottomLeftRadius(value: number): Background {
|
||||
let clone = this.clone();
|
||||
const clone = this.clone();
|
||||
clone.borderBottomLeftRadius = value;
|
||||
return clone;
|
||||
}
|
||||
|
||||
public withClipPath(value: string): Background {
|
||||
let clone = this.clone();
|
||||
const clone = this.clone();
|
||||
clone.clipPath = value;
|
||||
return clone;
|
||||
}
|
||||
|
||||
public getDrawParams(width: number, height: number): BackgroundDrawParams {
|
||||
if (!this.image) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let res: BackgroundDrawParams = {
|
||||
repeatX: true,
|
||||
repeatY: true,
|
||||
posX: 0,
|
||||
posY: 0,
|
||||
}
|
||||
|
||||
// repeat
|
||||
if (this.repeat) {
|
||||
switch (this.repeat.toLowerCase()) {
|
||||
case "no-repeat":
|
||||
res.repeatX = false;
|
||||
res.repeatY = false;
|
||||
break;
|
||||
|
||||
case "repeat-x":
|
||||
res.repeatY = false;
|
||||
break;
|
||||
|
||||
case "repeat-y":
|
||||
res.repeatX = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let imageWidth = this.image.width;
|
||||
let imageHeight = this.image.height;
|
||||
|
||||
// size
|
||||
if (this.size) {
|
||||
let values = cssParse(this.size);
|
||||
|
||||
if (values.length === 2) {
|
||||
let vx = values[0];
|
||||
let vy = values[1];
|
||||
if (vx.unit === "%" && vy.unit === "%") {
|
||||
imageWidth = width * vx.value / 100;
|
||||
imageHeight = height * vy.value / 100;
|
||||
|
||||
res.sizeX = imageWidth;
|
||||
res.sizeY = imageHeight;
|
||||
}
|
||||
else if (vx.type === "number" && vy.type === "number" &&
|
||||
((vx.unit === "px" && vy.unit === "px") || (vx.unit === "" && vy.unit === ""))) {
|
||||
imageWidth = vx.value;
|
||||
imageHeight = vy.value;
|
||||
|
||||
res.sizeX = imageWidth;
|
||||
res.sizeY = imageHeight;
|
||||
}
|
||||
}
|
||||
else if (values.length === 1 && values[0].type === "ident") {
|
||||
let scale = 0;
|
||||
|
||||
if (values[0].string === "cover") {
|
||||
scale = Math.max(width / imageWidth, height / imageHeight);
|
||||
}
|
||||
else if (values[0].string === "contain") {
|
||||
scale = Math.min(width / imageWidth, height / imageHeight);
|
||||
}
|
||||
|
||||
if (scale > 0) {
|
||||
imageWidth *= scale;
|
||||
imageHeight *= scale;
|
||||
|
||||
res.sizeX = imageWidth;
|
||||
res.sizeY = imageHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// position
|
||||
if (this.position) {
|
||||
let v = Background.parsePosition(this.position);
|
||||
if (v) {
|
||||
let spaceX = width - imageWidth;
|
||||
let spaceY = height - imageHeight;
|
||||
|
||||
if (v.x.unit === "%" && v.y.unit === "%") {
|
||||
res.posX = spaceX * v.x.value / 100;
|
||||
res.posY = spaceY * v.y.value / 100;
|
||||
}
|
||||
else if (v.x.type === "number" && v.y.type === "number" &&
|
||||
((v.x.unit === "px" && v.y.unit === "px") || (v.x.unit === "" && v.y.unit === ""))) {
|
||||
res.posX = v.x.value;
|
||||
res.posY = v.y.value;
|
||||
}
|
||||
else if (v.x.type === "ident" && v.y.type === "ident") {
|
||||
if (v.x.string.toLowerCase() === "center") {
|
||||
res.posX = spaceX / 2;
|
||||
}
|
||||
else if (v.x.string.toLowerCase() === "right") {
|
||||
res.posX = spaceX;
|
||||
}
|
||||
|
||||
if (v.y.string.toLowerCase() === "center") {
|
||||
res.posY = spaceY / 2;
|
||||
}
|
||||
else if (v.y.string.toLowerCase() === "bottom") {
|
||||
res.posY = spaceY;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
private static parsePosition(pos: string): { x: CSSValue, y: CSSValue } {
|
||||
let values = cssParse(pos);
|
||||
|
||||
if (values.length === 2) {
|
||||
return {
|
||||
x: values[0],
|
||||
y: values[1]
|
||||
};
|
||||
}
|
||||
|
||||
if (values.length === 1 && values[0].type === "ident") {
|
||||
let val = values[0].string.toLocaleLowerCase();
|
||||
let center = {
|
||||
type: "ident",
|
||||
string: "center"
|
||||
};
|
||||
|
||||
// If you only one keyword is specified, the other value is "center"
|
||||
if (val === "left" || val === "right") {
|
||||
return {
|
||||
x: values[0],
|
||||
y: center
|
||||
};
|
||||
}
|
||||
|
||||
else if (val === "top" || val === "bottom") {
|
||||
return {
|
||||
x: center,
|
||||
y: values[0]
|
||||
};
|
||||
}
|
||||
|
||||
else if (val === "center") {
|
||||
return {
|
||||
x: center,
|
||||
y: center
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
public isEmpty(): boolean {
|
||||
return !this.color
|
||||
&& !this.image
|
||||
|
@ -1,10 +1,14 @@
|
||||
import { View } from "../core/view";
|
||||
import { isNullOrUndefined, isFunction, getClass } from "../../utils/types";
|
||||
import { CacheLayerType, layout } from "../../utils/utils";
|
||||
import { CacheLayerType, isDataURI, isFileOrResourcePath, layout, RESOURCE_PREFIX, FILE_PREFIX } from "../../utils/utils";
|
||||
import { parse } from "../../css-value";
|
||||
|
||||
import { path, knownFolders } from "../../file-system";
|
||||
import { android as androidApp } from "../../application";
|
||||
export * from "./background-common"
|
||||
|
||||
interface AndroidView {
|
||||
background: android.graphics.drawable.Drawable.ConstantState;
|
||||
}
|
||||
|
||||
// TODO: Change this implementation to use
|
||||
// We are using "ad" here to avoid namespace collision with the global android object
|
||||
export module ad {
|
||||
@ -17,8 +21,6 @@ export module ad {
|
||||
return SDK;
|
||||
}
|
||||
|
||||
let _defaultBackgrounds = new Map<string, android.graphics.drawable.Drawable.ConstantState>();
|
||||
|
||||
function isSetColorFilterOnlyWidget(nativeView: android.view.View): boolean {
|
||||
return (
|
||||
nativeView instanceof android.widget.Button ||
|
||||
@ -29,43 +31,40 @@ export module ad {
|
||||
}
|
||||
|
||||
export function onBackgroundOrBorderPropertyChanged(view: View) {
|
||||
let nativeView = <android.view.View>view.nativeView;
|
||||
const nativeView = <android.view.View>view.nativeView;
|
||||
if (!nativeView) {
|
||||
return;
|
||||
}
|
||||
|
||||
let background = view.style.backgroundInternal;
|
||||
let backgroundDrawable = nativeView.getBackground();
|
||||
let cache = <CacheLayerType>view.nativeView;
|
||||
let viewClass = getClass(view);
|
||||
|
||||
// always cache the default background constant state.
|
||||
if (!_defaultBackgrounds.has(viewClass) && !isNullOrUndefined(backgroundDrawable)) {
|
||||
_defaultBackgrounds.set(viewClass, backgroundDrawable.getConstantState());
|
||||
const background = view.style.backgroundInternal;
|
||||
const cache = <CacheLayerType>view.nativeView;
|
||||
const 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.background === undefined && drawable) {
|
||||
androidView.background = drawable.getConstantState();
|
||||
}
|
||||
|
||||
if (isSetColorFilterOnlyWidget(nativeView)
|
||||
&& !isNullOrUndefined(backgroundDrawable)
|
||||
&& isFunction(backgroundDrawable.setColorFilter)
|
||||
&& drawable
|
||||
&& !background.hasBorderWidth()
|
||||
&& !background.hasBorderRadius()
|
||||
&& !background.clipPath
|
||||
&& isNullOrUndefined(background.image)
|
||||
&& !isNullOrUndefined(background.color)) {
|
||||
let backgroundColor = (<any>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
|
||||
(<any>backgroundDrawable).backgroundColor = backgroundColor;
|
||||
}
|
||||
else if (!background.isEmpty()) {
|
||||
if (!(backgroundDrawable instanceof org.nativescript.widgets.BorderDrawable)) {
|
||||
&& !background.image
|
||||
&& background.color) {
|
||||
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 (!background.isEmpty()) {
|
||||
let backgroundDrawable = drawable as org.nativescript.widgets.BorderDrawable;
|
||||
if (!(drawable instanceof org.nativescript.widgets.BorderDrawable)) {
|
||||
backgroundDrawable = new org.nativescript.widgets.BorderDrawable(layout.getDisplayDensity(), view.toString());
|
||||
refreshBorderDrawable(view, <org.nativescript.widgets.BorderDrawable>backgroundDrawable);
|
||||
refreshBorderDrawable(view, backgroundDrawable);
|
||||
org.nativescript.widgets.ViewHelper.setBackground(nativeView, backgroundDrawable);
|
||||
}
|
||||
else {
|
||||
refreshBorderDrawable(view, <org.nativescript.widgets.BorderDrawable>backgroundDrawable);
|
||||
} else {
|
||||
refreshBorderDrawable(view, backgroundDrawable);
|
||||
}
|
||||
|
||||
// This should be done only when backgroundImage is set!!!
|
||||
@ -77,11 +76,11 @@ export module ad {
|
||||
cache.setLayerType(android.view.View.LAYER_TYPE_SOFTWARE, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (_defaultBackgrounds.has(viewClass)) {
|
||||
org.nativescript.widgets.ViewHelper.setBackground(nativeView, _defaultBackgrounds.get(viewClass).newDrawable());
|
||||
}
|
||||
} else {
|
||||
// TODO: newDrawable for BitmapDrawable will fail if we don't speicfy resource. Use the other overload.
|
||||
const defaultDrawable = androidView.background ? androidView.background.newDrawable() : null;
|
||||
org.nativescript.widgets.ViewHelper.setBackground(nativeView, defaultDrawable);
|
||||
androidView.background = undefined;
|
||||
|
||||
if (cache.layerType !== undefined) {
|
||||
cache.setLayerType(cache.layerType, null);
|
||||
@ -91,10 +90,10 @@ export module ad {
|
||||
|
||||
// TODO: Can we move BorderWidths as separate native setter?
|
||||
// This way we could skip setPadding if borderWidth is not changed.
|
||||
let leftPadding = Math.ceil(view.effectiveBorderLeftWidth + view.effectivePaddingLeft);
|
||||
let topPadding = Math.ceil(view.effectiveBorderTopWidth + view.effectivePaddingTop);
|
||||
let rightPadding = Math.ceil(view.effectiveBorderRightWidth + view.effectivePaddingRight);
|
||||
let bottomPadding = Math.ceil(view.effectiveBorderBottomWidth + view.effectivePaddingBottom);
|
||||
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,
|
||||
@ -105,25 +104,53 @@ export module ad {
|
||||
}
|
||||
}
|
||||
|
||||
function refreshBorderDrawable(view: View, borderDrawable: org.nativescript.widgets.BorderDrawable) {
|
||||
let background = view.style.backgroundInternal;
|
||||
function fromBase64(source: string): android.graphics.Bitmap {
|
||||
const bytes = android.util.Base64.decode(source, android.util.Base64.DEFAULT);
|
||||
return android.graphics.BitmapFactory.decodeByteArray(bytes, 0, bytes.length)
|
||||
}
|
||||
|
||||
const pattern: RegExp = /url\(('|")(.*?)\1\)/;
|
||||
function refreshBorderDrawable(this: void, view: View, borderDrawable: org.nativescript.widgets.BorderDrawable) {
|
||||
const nativeView = <android.view.View>view.nativeView;
|
||||
const context = nativeView.getContext();
|
||||
|
||||
const background = view.style.backgroundInternal;
|
||||
if (background) {
|
||||
let backgroundPositionParsedCSSValues: native.Array<org.nativescript.widgets.CSSValue> = null;
|
||||
let backgroundSizeParsedCSSValues: native.Array<org.nativescript.widgets.CSSValue> = null;
|
||||
if (background.position) {
|
||||
backgroundPositionParsedCSSValues = createNativeCSSValueArray(background.position);
|
||||
const backgroundPositionParsedCSSValues = createNativeCSSValueArray(background.position);
|
||||
const backgroundSizeParsedCSSValues = createNativeCSSValueArray(background.size);
|
||||
const blackColor = -16777216; //android.graphics.Color.BLACK;
|
||||
|
||||
let imageUri = background.image;
|
||||
if (imageUri) {
|
||||
const match = imageUri.match(pattern);
|
||||
if (match && match[2]) {
|
||||
imageUri = match[2];
|
||||
}
|
||||
}
|
||||
|
||||
let bitmap: android.graphics.Bitmap = null;
|
||||
if (isDataURI(imageUri)) {
|
||||
const base64Data = imageUri.split(",")[1];
|
||||
if (base64Data !== undefined) {
|
||||
bitmap = fromBase64(base64Data);
|
||||
imageUri = null;
|
||||
}
|
||||
} else if (isFileOrResourcePath(imageUri)) {
|
||||
if (imageUri.indexOf(RESOURCE_PREFIX) !== 0) {
|
||||
let fileName = imageUri;
|
||||
if (fileName.indexOf("~/") === 0) {
|
||||
fileName = path.join(knownFolders.currentApp().path, fileName.replace("~/", ""));
|
||||
}
|
||||
|
||||
imageUri = FILE_PREFIX + fileName;
|
||||
}
|
||||
if (background.size) {
|
||||
backgroundSizeParsedCSSValues = createNativeCSSValueArray(background.size);
|
||||
}
|
||||
|
||||
let blackColor = android.graphics.Color.BLACK;
|
||||
borderDrawable.refresh(
|
||||
|
||||
(background.borderTopColor && background.borderTopColor.android !== undefined) ? background.borderTopColor.android : blackColor,
|
||||
(background.borderRightColor && background.borderRightColor.android !== undefined) ? background.borderRightColor.android : blackColor,
|
||||
(background.borderBottomColor && background.borderBottomColor.android !== undefined) ? background.borderBottomColor.android : blackColor,
|
||||
(background.borderLeftColor && background.borderLeftColor.android !== undefined) ? background.borderLeftColor.android : blackColor,
|
||||
background.borderTopColor ? background.borderTopColor.android : blackColor,
|
||||
background.borderRightColor ? background.borderRightColor.android : blackColor,
|
||||
background.borderBottomColor ? background.borderBottomColor.android : blackColor,
|
||||
background.borderLeftColor ? background.borderLeftColor.android : blackColor,
|
||||
|
||||
background.borderTopWidth,
|
||||
background.borderRightWidth,
|
||||
@ -137,8 +164,10 @@ function refreshBorderDrawable(view: View, borderDrawable: org.nativescript.widg
|
||||
|
||||
background.clipPath,
|
||||
|
||||
(background.color && background.color.android) ? background.color.android : 0,
|
||||
(background.image && background.image.android) ? background.image.android : null,
|
||||
background.color ? background.color.android : 0,
|
||||
imageUri,
|
||||
bitmap,
|
||||
context,
|
||||
background.repeat,
|
||||
background.position,
|
||||
backgroundPositionParsedCSSValues,
|
||||
@ -154,8 +183,8 @@ function createNativeCSSValueArray(css: string): native.Array<org.nativescript.w
|
||||
return null;
|
||||
}
|
||||
|
||||
let cssValues = parse(css);
|
||||
let nativeArray = Array.create(org.nativescript.widgets.CSSValue, cssValues.length);
|
||||
const cssValues = parse(css);
|
||||
const nativeArray = Array.create(org.nativescript.widgets.CSSValue, cssValues.length);
|
||||
for (let i = 0, length = cssValues.length; i < length; i++) {
|
||||
nativeArray[i] = new org.nativescript.widgets.CSSValue(
|
||||
cssValues[i].type,
|
||||
@ -167,3 +196,48 @@ function createNativeCSSValueArray(css: string): native.Array<org.nativescript.w
|
||||
|
||||
return nativeArray;
|
||||
}
|
||||
|
||||
export enum CacheMode {
|
||||
none,
|
||||
memory,
|
||||
diskAndMemory
|
||||
}
|
||||
|
||||
let currentCacheMode: CacheMode;
|
||||
let imageFetcher: org.nativescript.widgets.image.Fetcher;
|
||||
|
||||
export function initImageCache(context: android.content.Context, mode = CacheMode.diskAndMemory, memoryCacheSize: number = 0.25, diskCacheSize: number = 10 * 1024 * 1024): void {
|
||||
if (currentCacheMode === mode) {
|
||||
return;
|
||||
}
|
||||
|
||||
currentCacheMode = mode;
|
||||
if (!imageFetcher) {
|
||||
imageFetcher = org.nativescript.widgets.image.Fetcher.getInstance(context);
|
||||
} else {
|
||||
imageFetcher.clearCache();
|
||||
}
|
||||
|
||||
const params = new org.nativescript.widgets.image.Cache.CacheParams();
|
||||
params.memoryCacheEnabled = mode !== CacheMode.none;
|
||||
params.setMemCacheSizePercent(memoryCacheSize); // Set memory cache to % of app memory
|
||||
params.diskCacheEnabled = mode === CacheMode.diskAndMemory;
|
||||
params.diskCacheSize = diskCacheSize;
|
||||
const imageCache = org.nativescript.widgets.image.Cache.getInstance(params);
|
||||
imageFetcher.addImageCache(imageCache);
|
||||
imageFetcher.initCache();
|
||||
}
|
||||
|
||||
androidApp.on("activityStarted", (args) => {
|
||||
if (!imageFetcher) {
|
||||
initImageCache(args.activity);
|
||||
} else {
|
||||
imageFetcher.initCache();
|
||||
}
|
||||
});
|
||||
|
||||
androidApp.on("activityStopped", (args) => {
|
||||
if (imageFetcher) {
|
||||
imageFetcher.closeCache();
|
||||
}
|
||||
});
|
18
tns-core-modules/ui/styling/background.d.ts
vendored
18
tns-core-modules/ui/styling/background.d.ts
vendored
@ -2,23 +2,13 @@
|
||||
* @module "ui/styling/background"
|
||||
*/ /** */
|
||||
|
||||
import { ImageSource } from "../../image-source";
|
||||
import { Color } from "../../color";
|
||||
import { View, BackgroundRepeat } from "../core/view";
|
||||
|
||||
export interface BackgroundDrawParams {
|
||||
repeatX: boolean;
|
||||
repeatY: boolean;
|
||||
posX: number;
|
||||
posY: number;
|
||||
sizeX?: number;
|
||||
sizeY?: number;
|
||||
}
|
||||
|
||||
export class Background {
|
||||
public static default: Background;
|
||||
public color: Color;
|
||||
public image: ImageSource;
|
||||
public image: string;
|
||||
public repeat: BackgroundRepeat;
|
||||
public position: string;
|
||||
public size: string;
|
||||
@ -37,7 +27,7 @@ export class Background {
|
||||
public clipPath: string;
|
||||
|
||||
public withColor(value: Color): Background;
|
||||
public withImage(value: ImageSource): Background;
|
||||
public withImage(value: string): Background;
|
||||
public withRepeat(value: BackgroundRepeat): Background;
|
||||
public withPosition(value: string): Background;
|
||||
public withSize(value: string): Background;
|
||||
@ -55,8 +45,6 @@ export class Background {
|
||||
public withBorderBottomLeftRadius(value: number): Background;
|
||||
public withClipPath(value: string): Background;
|
||||
|
||||
public getDrawParams(width: number, height: number): BackgroundDrawParams;
|
||||
|
||||
public isEmpty(): boolean;
|
||||
|
||||
public static equals(value1: Background, value2: Background): boolean;
|
||||
@ -74,7 +62,7 @@ export class Background {
|
||||
}
|
||||
|
||||
export module ios {
|
||||
export function createBackgroundUIColor(view: View, flip?: boolean): any /* UIColor */;
|
||||
export function createBackgroundUIColor(view: View, callback: (uiColor: any /* UIColor */) => void, flip?: boolean): void;
|
||||
}
|
||||
|
||||
export module ad {
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { Color } from "../../color";
|
||||
import { Background as BackgroundDefinition } from "./background";
|
||||
import { View, Point } from "../core/view";
|
||||
import { Background } from "./background-common";
|
||||
import { ios as utilsIos } from "../../utils/utils";
|
||||
import { layout } from "../../utils/utils";
|
||||
import { Color } from "../../color";
|
||||
import { ios as utilsIos, isDataURI, isFileOrResourcePath, layout } from "../../utils/utils";
|
||||
import { fromFileOrResource, fromBase64, fromUrl } from "../../image-source";
|
||||
import { CSSValue, parse as cssParse } from "../../css-value";
|
||||
|
||||
export * from "./background-common";
|
||||
|
||||
@ -22,10 +23,11 @@ interface Rect {
|
||||
}
|
||||
|
||||
const clearCGColor = utilsIos.getter(UIColor, UIColor.clearColor).CGColor;
|
||||
const symbolUrl = Symbol("backgroundImageUrl");
|
||||
|
||||
export module ios {
|
||||
export function createBackgroundUIColor(view: View, flip?: boolean): UIColor {
|
||||
const background = <Background>view.style.backgroundInternal;
|
||||
export function createBackgroundUIColor(view: View, callback: (uiColor: UIColor) => void, flip?: boolean): void {
|
||||
const background = view.style.backgroundInternal;
|
||||
const nativeView = <NativeView>view.nativeView;
|
||||
|
||||
if (background.hasUniformBorder()) {
|
||||
@ -52,9 +54,10 @@ export module ios {
|
||||
}
|
||||
|
||||
if (!background.image) {
|
||||
return background.color ? background.color.ios : undefined;
|
||||
const uiColor = background.color ? background.color.ios : undefined;
|
||||
callback(uiColor);
|
||||
} else {
|
||||
return getUIColorFromImage(view, nativeView, background, flip);
|
||||
setUIColorFromImage(view, nativeView, callback, flip);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -77,7 +80,8 @@ function clearNonUniformBorders(nativeView: NativeView): void {
|
||||
}
|
||||
}
|
||||
|
||||
function getUIColorFromImage(view: View, nativeView: UIView, background: Background, flip?: boolean): UIColor {
|
||||
const pattern: RegExp = /url\(('|")(.*?)\1\)/;
|
||||
function setUIColorFromImage(view: View, nativeView: UIView, callback: (uiColor: UIColor) => void, flip?: boolean): void {
|
||||
const frame = nativeView.frame;
|
||||
const boundsWidth = view.scaleX ? frame.size.width / view.scaleX : frame.size.width;
|
||||
const boundsHeight = view.scaleY ? frame.size.height / view.scaleY : frame.size.height;
|
||||
@ -85,9 +89,188 @@ function getUIColorFromImage(view: View, nativeView: UIView, background: Backgro
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// We have an image for a background
|
||||
let img = <UIImage>background.image.ios;
|
||||
const params = background.getDrawParams(boundsWidth, boundsHeight);
|
||||
const style = view.style;
|
||||
const background = style.backgroundInternal;
|
||||
let imageUri = background.image;
|
||||
if (imageUri) {
|
||||
const match = imageUri.match(pattern);
|
||||
if (match && match[2]) {
|
||||
imageUri = match[2];
|
||||
}
|
||||
}
|
||||
|
||||
let bitmap: UIImage;
|
||||
if (isDataURI(imageUri)) {
|
||||
const base64Data = imageUri.split(",")[1];
|
||||
if (base64Data !== undefined) {
|
||||
bitmap = fromBase64(base64Data).ios
|
||||
}
|
||||
} else if (isFileOrResourcePath(imageUri)) {
|
||||
bitmap = fromFileOrResource(imageUri).ios;
|
||||
} else if (imageUri.indexOf("http") !== -1) {
|
||||
style[symbolUrl] = imageUri;
|
||||
fromUrl(imageUri).then((r) => {
|
||||
if (style && style[symbolUrl] === imageUri) {
|
||||
uiColorFromImage(r.ios, view, callback, flip);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
uiColorFromImage(bitmap, view, callback, flip);
|
||||
}
|
||||
|
||||
interface BackgroundDrawParams {
|
||||
repeatX: boolean;
|
||||
repeatY: boolean;
|
||||
posX: number;
|
||||
posY: number;
|
||||
sizeX?: number;
|
||||
sizeY?: number;
|
||||
}
|
||||
|
||||
function parsePosition(pos: string): { x: CSSValue, y: CSSValue } {
|
||||
const values = cssParse(pos);
|
||||
if (values.length === 2) {
|
||||
return { x: values[0], y: values[1] };
|
||||
}
|
||||
|
||||
if (values.length === 1 && values[0].type === "ident") {
|
||||
const val = values[0].string.toLocaleLowerCase();
|
||||
const center = { type: "ident", string: "center" };
|
||||
|
||||
// If you only one keyword is specified, the other value is "center"
|
||||
if (val === "left" || val === "right") {
|
||||
return { x: values[0], y: center };
|
||||
} else if (val === "top" || val === "bottom") {
|
||||
return { x: center, y: values[0] };
|
||||
} else if (val === "center") {
|
||||
return { x: center, y: center };
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
function getDrawParams(this: void, image: UIImage, background: BackgroundDefinition, width: number, height: number): BackgroundDrawParams {
|
||||
if (!image) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const res: BackgroundDrawParams = {
|
||||
repeatX: true,
|
||||
repeatY: true,
|
||||
posX: 0,
|
||||
posY: 0,
|
||||
}
|
||||
|
||||
// repeat
|
||||
if (background.repeat) {
|
||||
switch (background.repeat.toLowerCase()) {
|
||||
case "no-repeat":
|
||||
res.repeatX = false;
|
||||
res.repeatY = false;
|
||||
break;
|
||||
|
||||
case "repeat-x":
|
||||
res.repeatY = false;
|
||||
break;
|
||||
|
||||
case "repeat-y":
|
||||
res.repeatX = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const imageSize = image.size;
|
||||
let imageWidth = imageSize.width;
|
||||
let imageHeight = imageSize.height;
|
||||
|
||||
// size
|
||||
const size = background.size;
|
||||
if (size) {
|
||||
const values = cssParse(size);
|
||||
if (values.length === 2) {
|
||||
const vx = values[0];
|
||||
const vy = values[1];
|
||||
if (vx.unit === "%" && vy.unit === "%") {
|
||||
imageWidth = width * vx.value / 100;
|
||||
imageHeight = height * vy.value / 100;
|
||||
|
||||
res.sizeX = imageWidth;
|
||||
res.sizeY = imageHeight;
|
||||
} else if (vx.type === "number" && vy.type === "number" &&
|
||||
((vx.unit === "px" && vy.unit === "px") || (vx.unit === "" && vy.unit === ""))) {
|
||||
imageWidth = vx.value;
|
||||
imageHeight = vy.value;
|
||||
|
||||
res.sizeX = imageWidth;
|
||||
res.sizeY = imageHeight;
|
||||
}
|
||||
}
|
||||
else if (values.length === 1 && values[0].type === "ident") {
|
||||
let scale = 0;
|
||||
if (values[0].string === "cover") {
|
||||
scale = Math.max(width / imageWidth, height / imageHeight);
|
||||
} else if (values[0].string === "contain") {
|
||||
scale = Math.min(width / imageWidth, height / imageHeight);
|
||||
}
|
||||
|
||||
if (scale > 0) {
|
||||
imageWidth *= scale;
|
||||
imageHeight *= scale;
|
||||
|
||||
res.sizeX = imageWidth;
|
||||
res.sizeY = imageHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// position
|
||||
const position = background.position;
|
||||
if (position) {
|
||||
const v = parsePosition(position);
|
||||
if (v) {
|
||||
const spaceX = width - imageWidth;
|
||||
const spaceY = height - imageHeight;
|
||||
|
||||
if (v.x.unit === "%" && v.y.unit === "%") {
|
||||
res.posX = spaceX * v.x.value / 100;
|
||||
res.posY = spaceY * v.y.value / 100;
|
||||
} else if (v.x.type === "number" && v.y.type === "number" &&
|
||||
((v.x.unit === "px" && v.y.unit === "px") || (v.x.unit === "" && v.y.unit === ""))) {
|
||||
res.posX = v.x.value;
|
||||
res.posY = v.y.value;
|
||||
} else if (v.x.type === "ident" && v.y.type === "ident") {
|
||||
if (v.x.string.toLowerCase() === "center") {
|
||||
res.posX = spaceX / 2;
|
||||
} else if (v.x.string.toLowerCase() === "right") {
|
||||
res.posX = spaceX;
|
||||
}
|
||||
|
||||
if (v.y.string.toLowerCase() === "center") {
|
||||
res.posY = spaceY / 2;
|
||||
} else if (v.y.string.toLowerCase() === "bottom") {
|
||||
res.posY = spaceY;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
function uiColorFromImage(img: UIImage, view: View, callback: (uiColor: UIColor) => void, flip?: boolean): void {
|
||||
if (!img) {
|
||||
callback(null);
|
||||
}
|
||||
|
||||
const nativeView = view.nativeView as UIView;
|
||||
const background = view.style.backgroundInternal;
|
||||
const frame = nativeView.frame;
|
||||
const boundsWidth = view.scaleX ? frame.size.width / view.scaleX : frame.size.width;
|
||||
const boundsHeight = view.scaleY ? frame.size.height / view.scaleY : frame.size.height;
|
||||
|
||||
const params = getDrawParams(img, background, boundsWidth, boundsHeight);
|
||||
|
||||
if (params.sizeX > 0 && params.sizeY > 0) {
|
||||
const resizeRect = CGRectMake(0, 0, params.sizeX, params.sizeY);
|
||||
@ -126,10 +309,10 @@ function getUIColorFromImage(view: View, nativeView: UIView, background: Backgro
|
||||
|
||||
if (flip) {
|
||||
const flippedImage = _flipImage(bkgImage);
|
||||
return UIColor.alloc().initWithPatternImage(flippedImage);
|
||||
callback(UIColor.alloc().initWithPatternImage(flippedImage));
|
||||
} else {
|
||||
callback(UIColor.alloc().initWithPatternImage(bkgImage));
|
||||
}
|
||||
|
||||
return UIColor.alloc().initWithPatternImage(bkgImage);
|
||||
}
|
||||
|
||||
// Flipping the default coordinate system
|
||||
@ -158,7 +341,7 @@ function cssValueToDeviceIndependentPixels(source: string, total: number): numbe
|
||||
}
|
||||
}
|
||||
|
||||
function drawNonUniformBorders(nativeView: NativeView, background: Background) {
|
||||
function drawNonUniformBorders(nativeView: NativeView, background: BackgroundDefinition) {
|
||||
const layer = nativeView.layer;
|
||||
layer.borderColor = undefined;
|
||||
layer.borderWidth = 0;
|
||||
@ -284,7 +467,7 @@ function drawNonUniformBorders(nativeView: NativeView, background: Background) {
|
||||
nativeView.hasNonUniformBorder = hasNonUniformBorder;
|
||||
}
|
||||
|
||||
function drawClipPath(nativeView: UIView, background: Background) {
|
||||
function drawClipPath(nativeView: UIView, background: BackgroundDefinition) {
|
||||
const layer = nativeView.layer;
|
||||
const layerBounds = layer.bounds;
|
||||
const layerOrigin = layerBounds.origin;
|
||||
|
@ -1,12 +1,9 @@
|
||||
import { Color } from "../../color";
|
||||
import { Font, parseFont, FontStyle, FontWeight } from "./font";
|
||||
import { isDataURI, isFileOrResourcePath, layout } from "../../utils/utils";
|
||||
import { layout } from "../../utils/utils";
|
||||
import { Background } from "./background";
|
||||
import { isIOS } from "../../platform";
|
||||
|
||||
// TODO: Remove this and start using string as source (for android).
|
||||
import { fromFileOrResource, fromBase64, fromUrl } from "../../image-source";
|
||||
|
||||
import { Style } from "./style";
|
||||
|
||||
import { unsetValue, CssProperty, CssAnimationProperty, ShorthandProperty, InheritedCssProperty, makeValidator, makeParser } from "../core/properties";
|
||||
@ -522,54 +519,11 @@ export const backgroundInternalProperty = new CssProperty<Style, Background>({
|
||||
});
|
||||
backgroundInternalProperty.register(Style);
|
||||
|
||||
let pattern: RegExp = /url\(('|")(.*?)\1\)/;
|
||||
// const pattern: RegExp = /url\(('|")(.*?)\1\)/;
|
||||
export const backgroundImageProperty = new CssProperty<Style, string>({
|
||||
name: "backgroundImage", cssName: "background-image", valueChanged: (target, oldValue, newValue) => {
|
||||
|
||||
let style = target;
|
||||
let currentBackground = target.backgroundInternal;
|
||||
let url: string = newValue;
|
||||
let isValid = false;
|
||||
|
||||
if (url === undefined) {
|
||||
style.backgroundInternal = currentBackground.withImage(undefined);
|
||||
return;
|
||||
}
|
||||
|
||||
let match = url.match(pattern);
|
||||
if (match && match[2]) {
|
||||
url = match[2];
|
||||
}
|
||||
|
||||
if (isDataURI(url)) {
|
||||
let base64Data = url.split(",")[1];
|
||||
if (typeof base64Data !== "undefined") {
|
||||
style.backgroundInternal = currentBackground.withImage(fromBase64(base64Data));
|
||||
isValid = true;
|
||||
} else {
|
||||
style.backgroundInternal = currentBackground.withImage(undefined);
|
||||
}
|
||||
}
|
||||
else if (isFileOrResourcePath(url)) {
|
||||
style.backgroundInternal = currentBackground.withImage(fromFileOrResource(url));
|
||||
isValid = true;
|
||||
}
|
||||
else if (url.indexOf("http") !== -1) {
|
||||
style["_url"] = url;
|
||||
style.backgroundInternal = currentBackground.withImage(undefined);
|
||||
fromUrl(url).then((r) => {
|
||||
if (style && style["_url"] === url) {
|
||||
// Get the current background again, as it might have changed while doing the request.
|
||||
currentBackground = target.backgroundInternal;
|
||||
target.backgroundInternal = currentBackground.withImage(r);
|
||||
}
|
||||
});
|
||||
isValid = true;
|
||||
}
|
||||
|
||||
if (!isValid) {
|
||||
style.backgroundInternal = currentBackground.withImage(undefined);
|
||||
}
|
||||
let background = target.backgroundInternal;
|
||||
target.backgroundInternal = background.withImage(newValue);
|
||||
}
|
||||
});
|
||||
backgroundImageProperty.register(Style);
|
||||
|
@ -1,6 +1,7 @@
|
||||
import * as types from "./types";
|
||||
|
||||
export var RESOURCE_PREFIX = "res://";
|
||||
export const RESOURCE_PREFIX = "res://";
|
||||
export const FILE_PREFIX = "file:///";
|
||||
|
||||
export function escapeRegexSymbols(source: string): string {
|
||||
let escapeRegex = /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g;
|
||||
@ -116,8 +117,7 @@ export function isDataURI(uri: string): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
var firstSegment = uri.trim().split(',')[0];
|
||||
|
||||
const firstSegment = uri.trim().split(',')[0];
|
||||
return firstSegment && firstSegment.indexOf("data:") === 0 && firstSegment.indexOf('base64') >= 0;
|
||||
}
|
||||
|
||||
|
3
tns-core-modules/utils/utils.d.ts
vendored
3
tns-core-modules/utils/utils.d.ts
vendored
@ -2,7 +2,8 @@
|
||||
* @module "utils/utils"
|
||||
*/ /** */
|
||||
|
||||
export var RESOURCE_PREFIX: string;
|
||||
export const RESOURCE_PREFIX: string;
|
||||
export const FILE_PREFIX: string;
|
||||
|
||||
//@private
|
||||
/**
|
||||
|
@ -71,7 +71,9 @@
|
||||
clipPath: string,
|
||||
|
||||
backgroundColor: number,
|
||||
backgroundImage: android.graphics.Bitmap,
|
||||
backgroundImage: string,
|
||||
backgroundBitmap: android.graphics.Bitmap,
|
||||
context: android.content.Context,
|
||||
backgroundRepeat: string,
|
||||
backgroundPosition: string,
|
||||
backgroundPositionParsedCSSValues: native.Array<CSSValue>,
|
||||
@ -100,7 +102,9 @@
|
||||
public getClipPath(): string;
|
||||
|
||||
public getBackgroundColor(): number;
|
||||
public getBackgroundImage(): android.graphics.Bitmap;
|
||||
public getBackgroundImage(): string;
|
||||
public getBackgroundBitmap(): android.graphics.Bitmap;
|
||||
|
||||
public getBackgroundRepeat(): string;
|
||||
public getBackgroundPosition(): string;
|
||||
public getBackgroundSize(): string;
|
||||
@ -401,6 +405,7 @@
|
||||
public addImageCache(cache: Cache): void;
|
||||
public initCache(): void;
|
||||
public clearCache(): void;
|
||||
public closeCache(): void;
|
||||
public loadImage(data: Object, imageView: ImageView,
|
||||
decodeWidth: number, decodeHeight: number, useCache: boolean, async: boolean,
|
||||
listener: Worker.IOnImageLoadedListener): void;
|
||||
|
Reference in New Issue
Block a user