Files
NativeScript/tns-core-modules/ui/image/image.android.ts
Dimitar Tachev a94ec9946f Improve ImageAsset scaling (#5110)
* Do not depend on current device screen while calculating Image Asset size.

* Scale the image asset to the exact requested size.

* Process image assets natively, pass keepAspectRatio based on the stretch property and Asset options.

* Fixed the splashscreen resource name as it cannot be read when containing a dot.

* Updated the Image Asset scale and rotate logic based on the Native one.

* Make the ImageAsset size more important than the Image decode size as its more specific.

* Fixed tslint errors.

* Added filePath support in the ImageAsset constructor for iOS in order to unify it with the Android implementation, support for relative files and file not found support errors.

* Added unit tests for ImageAssets.

* Added a sample app for UI testing of image-view with ImageAsset src.

* chore: apply PR comments
2018-02-28 14:04:01 +02:00

191 lines
6.4 KiB
TypeScript

import {
ImageSource, ImageAsset, ImageBase, stretchProperty, imageSourceProperty, srcProperty, tintColorProperty, Color,
isDataURI, isFileOrResourcePath, RESOURCE_PREFIX
} from "./image-common";
import { knownFolders } from "../../file-system";
import * as platform from "../../platform";
export * from "./image-common";
const FILE_PREFIX = "file:///";
const ASYNC = "async";
let AndroidImageView: typeof org.nativescript.widgets.ImageView;
interface ImageLoadedListener {
new (owner: Image): org.nativescript.widgets.image.Worker.OnImageLoadedListener;
}
let ImageLoadedListener: ImageLoadedListener;
function initializeImageLoadedListener() {
if (ImageLoadedListener) {
return;
}
@Interfaces([org.nativescript.widgets.image.Worker.OnImageLoadedListener])
class ImageLoadedListenerImpl extends java.lang.Object implements org.nativescript.widgets.image.Worker.OnImageLoadedListener {
constructor(public owner: Image) {
super();
return global.__native(this);
}
onImageLoaded(success: boolean): void {
const owner = this.owner;
if (owner) {
owner.isLoading = false;
}
}
}
ImageLoadedListener = ImageLoadedListenerImpl;
}
export class Image extends ImageBase {
nativeViewProtected: org.nativescript.widgets.ImageView;
public decodeWidth = 0;
public decodeHeight = 0;
public useCache = true;
public createNativeView() {
if (!AndroidImageView) {
AndroidImageView = org.nativescript.widgets.ImageView;
}
initializeImageLoadedListener();
const imageView = new AndroidImageView(this._context);
const listener = new ImageLoadedListener(this);
imageView.setImageLoadedListener(listener);
(<any>imageView).listener = listener;
return imageView;
}
public initNativeView(): void {
super.initNativeView();
(<any>this.nativeViewProtected).listener.owner = this;
}
public disposeNativeView() {
(<any>this.nativeViewProtected).listener.owner = null;
super.disposeNativeView();
}
public resetNativeView(): void {
super.resetNativeView();
this.nativeViewProtected.setImageMatrix(new android.graphics.Matrix());
}
public _createImageSourceFromSrc(value: string | ImageSource | ImageAsset) {
const imageView = this.nativeViewProtected;
if (!imageView) {
return;
}
if (!value) {
imageView.setUri(null, 0, 0, false, false, true);
return;
}
let screen = platform.screen.mainScreen;
let decodeWidth = Math.min(this.decodeWidth, screen.widthPixels);
let decodeHeight = Math.min(this.decodeHeight, screen.heightPixels);
let keepAspectRatio = this._calculateKeepAspectRatio();
if (value instanceof ImageAsset) {
if (value.options) {
decodeWidth = value.options.width || decodeWidth;
decodeHeight = value.options.height || decodeHeight;
keepAspectRatio = !!value.options.keepAspectRatio;
}
// handle assets as file paths natively
value = value.android;
}
const async = this.loadMode === ASYNC;
if (typeof value === "string" || value instanceof String) {
value = value.trim();
this.isLoading = true;
if (isDataURI(value)) {
// TODO: Check with runtime what should we do in case of base64 string.
super._createImageSourceFromSrc(value);
} else if (isFileOrResourcePath(value)) {
if (value.indexOf(RESOURCE_PREFIX) === 0) {
imageView.setUri(value, decodeWidth, decodeHeight, keepAspectRatio, this.useCache, async);
} else {
let fileName = value;
if (fileName.indexOf("~/") === 0) {
fileName = knownFolders.currentApp().path + "/" + fileName.replace("~/", "");
}
imageView.setUri(FILE_PREFIX + fileName, decodeWidth, decodeHeight, keepAspectRatio, this.useCache, async);
}
} else {
// For backwards compatibility http always use async loading.
imageView.setUri(value, decodeWidth, decodeHeight, keepAspectRatio, this.useCache, true);
}
} else {
super._createImageSourceFromSrc(value);
}
}
private _calculateKeepAspectRatio(): boolean {
return this.stretch === "fill" ? false : true;
}
[stretchProperty.getDefault](): "aspectFit" {
return "aspectFit";
}
[stretchProperty.setNative](value: "none" | "aspectFill" | "aspectFit" | "fill") {
switch (value) {
case "aspectFit":
this.nativeViewProtected.setScaleType(android.widget.ImageView.ScaleType.FIT_CENTER);
break;
case "aspectFill":
this.nativeViewProtected.setScaleType(android.widget.ImageView.ScaleType.CENTER_CROP);
break;
case "fill":
this.nativeViewProtected.setScaleType(android.widget.ImageView.ScaleType.FIT_XY);
break;
case "none":
default:
this.nativeViewProtected.setScaleType(android.widget.ImageView.ScaleType.MATRIX);
break;
}
}
[tintColorProperty.getDefault](): Color {
return undefined;
}
[tintColorProperty.setNative](value: Color) {
if (value === undefined) {
this.nativeViewProtected.clearColorFilter();
} else {
this.nativeViewProtected.setColorFilter(value.android);
}
}
[imageSourceProperty.getDefault](): ImageSource {
return undefined;
}
[imageSourceProperty.setNative](value: ImageSource) {
const nativeView = this.nativeViewProtected;
if (value && value.android) {
const rotation = value.rotationAngle ? value.rotationAngle : 0;
nativeView.setRotationAngle(rotation);
nativeView.setImageBitmap(value.android);
} else {
nativeView.setRotationAngle(0);
nativeView.setImageBitmap(null);
}
}
[srcProperty.getDefault](): any {
return undefined;
}
[srcProperty.setNative](value: any) {
this._createImageSourceFromSrc(value);
}
}