mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-05 13:26:48 +08:00
feat(android): vector drawable support (#9464)
This commit is contained in:
committed by
Nathan Walker
parent
b2f792324d
commit
76499a5367
@@ -7,6 +7,9 @@ import android.content.Context;
|
||||
import android.graphics.*;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.shapes.RoundRectShape;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
|
||||
import org.nativescript.widgets.image.BitmapOwner;
|
||||
import org.nativescript.widgets.image.Fetcher;
|
||||
@@ -14,7 +17,7 @@ import org.nativescript.widgets.image.Worker;
|
||||
/**
|
||||
* @author hhristov
|
||||
*/
|
||||
public class ImageView extends android.widget.ImageView implements BitmapOwner {
|
||||
public class ImageView extends androidx.appcompat.widget.AppCompatImageView implements BitmapOwner {
|
||||
private static final double EPSILON = 1E-05;
|
||||
|
||||
private Path path = new Path();
|
||||
@@ -36,6 +39,10 @@ public class ImageView extends android.widget.ImageView implements BitmapOwner {
|
||||
private Worker.OnImageLoadedListener mListener;
|
||||
private boolean mAttachedToWindow = false;
|
||||
|
||||
static {
|
||||
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
|
||||
}
|
||||
|
||||
public float getRotationAngle() {
|
||||
return rotationAngle;
|
||||
}
|
||||
@@ -214,7 +221,9 @@ public class ImageView extends android.widget.ImageView implements BitmapOwner {
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
BorderDrawable background = this.getBackground() instanceof BorderDrawable ? (BorderDrawable) this.getBackground() : null;
|
||||
|
||||
if(this.mBitmap == null && this.getDrawable() != null) {
|
||||
super.onDraw(canvas);
|
||||
}
|
||||
if (this.mBitmap != null) {
|
||||
float borderTopLeftRadius, borderTopRightRadius, borderBottomRightRadius, borderBottomLeftRadius;
|
||||
|
||||
@@ -332,4 +341,4 @@ public class ImageView extends android.widget.ImageView implements BitmapOwner {
|
||||
public void setDrawable(Drawable asyncDrawable) {
|
||||
this.setImageDrawable(asyncDrawable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.nativescript.widgets;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Color;
|
||||
@@ -18,6 +19,7 @@ import android.util.Pair;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.appcompat.content.res.AppCompatResources;
|
||||
import androidx.exifinterface.media.ExifInterface;
|
||||
|
||||
import org.json.JSONException;
|
||||
@@ -31,7 +33,18 @@ import java.io.IOException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
|
||||
public class Utils {
|
||||
public static Drawable getDrawable(String uri, Context context){
|
||||
String resPath = uri.substring("res://".length());
|
||||
int resId = context.getResources().getIdentifier(resPath, "drawable", context.getPackageName());
|
||||
if (resId > 0) {
|
||||
return AppCompatResources.getDrawable(context, resId);
|
||||
} else {
|
||||
Log.v("JS", "Missing Image with resourceID: " + uri);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public static void drawBoxShadow(View view, String value) {
|
||||
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M) {
|
||||
return;
|
||||
|
||||
@@ -20,16 +20,15 @@ import android.annotation.TargetApi;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import androidx.exifinterface.media.ExifInterface;
|
||||
import android.graphics.Matrix;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import androidx.exifinterface.media.ExifInterface;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
@@ -377,13 +376,12 @@ public class Fetcher extends Worker {
|
||||
// Decode bitmap with inSampleSize set
|
||||
options.inJustDecodeBounds = false;
|
||||
Bitmap bitmap = null;
|
||||
InputStream is = null;
|
||||
InputStream is = null;
|
||||
|
||||
try {
|
||||
final TypedValue value = new TypedValue();
|
||||
is = res.openRawResource(resId, value);
|
||||
|
||||
bitmap = BitmapFactory.decodeResourceStream(res, value, is, null, options);
|
||||
final TypedValue value = new TypedValue();
|
||||
is = res.openRawResource(resId, value);
|
||||
bitmap = BitmapFactory.decodeResourceStream(res, value, is, null, options);
|
||||
} catch (Exception e) {
|
||||
/* do nothing.
|
||||
If the exception happened on open, bm will be null.
|
||||
@@ -391,8 +389,10 @@ public class Fetcher extends Worker {
|
||||
*/
|
||||
}
|
||||
|
||||
if (bitmap == null && options != null && options.inBitmap != null) {
|
||||
throw new IllegalArgumentException("Problem decoding into existing bitmap");
|
||||
|
||||
if (bitmap == null) {
|
||||
// throw new IllegalArgumentException("Problem decoding into existing bitmap");
|
||||
return null;
|
||||
}
|
||||
|
||||
ExifInterface ei = getExifInterface(is);
|
||||
@@ -449,7 +449,7 @@ public class Fetcher extends Worker {
|
||||
/**
|
||||
* Decode and sample down a bitmap from a file to the requested width and height.
|
||||
*
|
||||
* @param filename The full path of the file to decode
|
||||
* @param fileName The full path of the file to decode
|
||||
* @param reqWidth The requested width of the resulting bitmap
|
||||
* @param reqHeight The requested height of the resulting bitmap
|
||||
* @param cache The Cache used to find candidate bitmaps for use with inBitmap
|
||||
@@ -26,9 +26,10 @@ import android.graphics.BitmapFactory;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.Log;
|
||||
import android.widget.ImageView;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import org.nativescript.widgets.Utils;
|
||||
|
||||
/**
|
||||
* This class wraps up completing some arbitrary long running work when loading a bitmap to an
|
||||
* ImageView. It handles things like using a memory and disk cache, running the work in a background
|
||||
@@ -52,6 +53,7 @@ public abstract class Worker {
|
||||
protected boolean mPauseWork = false;
|
||||
protected Resources mResources;
|
||||
protected ContentResolver mResolver;
|
||||
protected Context mContext;
|
||||
private static final int MESSAGE_CLEAR = 0;
|
||||
private static final int MESSAGE_INIT_DISK_CACHE = 1;
|
||||
private static final int MESSAGE_FLUSH = 2;
|
||||
@@ -62,6 +64,7 @@ public abstract class Worker {
|
||||
protected Worker(Context context) {
|
||||
mResources = context.getResources();
|
||||
mResolver = context.getContentResolver();
|
||||
mContext = context;
|
||||
// Negative means not initialized.
|
||||
if (debuggable < 0) {
|
||||
try {
|
||||
@@ -102,7 +105,7 @@ public abstract class Worker {
|
||||
return;
|
||||
}
|
||||
|
||||
Bitmap value = null;
|
||||
Object value = null;
|
||||
String cacheUri = uri;
|
||||
|
||||
if (debuggable > 0) {
|
||||
@@ -124,9 +127,14 @@ public abstract class Worker {
|
||||
if (debuggable > 0) {
|
||||
Log.v(TAG, "loadImage.addBitmapToCache: " + owner + ", src: " + cacheUri);
|
||||
}
|
||||
mCache.addBitmapToCache(cacheUri, value);
|
||||
mCache.addBitmapToCache(cacheUri, (Bitmap) value);
|
||||
}
|
||||
}
|
||||
|
||||
/* Try loading as drawable */
|
||||
if(value == null){
|
||||
value = Utils.getDrawable(uri, mContext);
|
||||
}
|
||||
}
|
||||
|
||||
if (value != null) {
|
||||
@@ -134,7 +142,12 @@ public abstract class Worker {
|
||||
if (debuggable > 0) {
|
||||
Log.v(TAG, "Set ImageBitmap on: " + owner + " to: " + uri);
|
||||
}
|
||||
owner.setBitmap(value);
|
||||
if(value instanceof Drawable){
|
||||
owner.setDrawable((Drawable) value);
|
||||
}else {
|
||||
owner.setBitmap((Bitmap) value);
|
||||
}
|
||||
|
||||
if (listener != null) {
|
||||
if (debuggable > 0) {
|
||||
Log.v(TAG, "OnImageLoadedListener on: " + owner + " to: " + uri);
|
||||
@@ -145,6 +158,8 @@ public abstract class Worker {
|
||||
final BitmapWorkerTask task = new BitmapWorkerTask(uri, owner, decodeWidth, decodeHeight, keepAspectRatio, useCache, listener);
|
||||
final AsyncDrawable asyncDrawable =
|
||||
new AsyncDrawable(mResources, mLoadingBitmap, task);
|
||||
|
||||
|
||||
owner.setDrawable(asyncDrawable);
|
||||
|
||||
// NOTE: This uses a custom version of AsyncTask that has been pulled from the
|
||||
@@ -277,7 +292,7 @@ public abstract class Worker {
|
||||
/**
|
||||
* The actual AsyncTask that will asynchronously process the image.
|
||||
*/
|
||||
private class BitmapWorkerTask extends AsyncTask<Void, Void, Bitmap> {
|
||||
private class BitmapWorkerTask extends AsyncTask<Void, Void, Object> {
|
||||
private int mDecodeWidth;
|
||||
private int mDecodeHeight;
|
||||
private boolean mKeepAspectRatio;
|
||||
@@ -306,13 +321,13 @@ public abstract class Worker {
|
||||
* Background processing.
|
||||
*/
|
||||
@Override
|
||||
protected Bitmap doInBackground(Void... params) {
|
||||
protected Object doInBackground(Void... params) {
|
||||
if (debuggable > 0) {
|
||||
Log.v(TAG, "doInBackground - starting work: " + imageViewReference.get() + ", on: " + mUri);
|
||||
}
|
||||
|
||||
|
||||
Bitmap bitmap = null;
|
||||
Object bitmap = null;
|
||||
|
||||
// Wait here if work is paused and the task is not cancelled
|
||||
synchronized (mPauseWorkLock) {
|
||||
@@ -327,8 +342,7 @@ public abstract class Worker {
|
||||
// another thread and the ImageView that was originally bound to this task is still
|
||||
// bound back to this task and our "exit early" flag is not set, then call the main
|
||||
// process method (as implemented by a subclass)
|
||||
if (bitmap == null && !isCancelled() && getAttachedOwner() != null
|
||||
&& !mExitTasksEarly) {
|
||||
if (!isCancelled() && getAttachedOwner() != null && !mExitTasksEarly) {
|
||||
bitmap = processBitmap(mUri, mDecodeWidth, mDecodeHeight, mKeepAspectRatio, mCacheImage);
|
||||
}
|
||||
|
||||
@@ -341,10 +355,15 @@ public abstract class Worker {
|
||||
if (debuggable > 0) {
|
||||
Log.v(TAG, "addBitmapToCache: " + imageViewReference.get() + ", src: " + mCacheUri);
|
||||
}
|
||||
mCache.addBitmapToCache(mCacheUri, bitmap);
|
||||
mCache.addBitmapToCache(mCacheUri, (Bitmap) bitmap);
|
||||
}
|
||||
}
|
||||
|
||||
/* Try loading as Drawable */
|
||||
if (bitmap == null){
|
||||
bitmap = Utils.getDrawable(mUri, mContext);
|
||||
}
|
||||
|
||||
if (debuggable > 0) {
|
||||
Log.v(TAG, "doInBackground - finished work");
|
||||
}
|
||||
@@ -356,7 +375,7 @@ public abstract class Worker {
|
||||
* Once the image is processed, associates it to the imageView
|
||||
*/
|
||||
@Override
|
||||
protected void onPostExecute(Bitmap value) {
|
||||
protected void onPostExecute(Object value) {
|
||||
boolean success = false;
|
||||
// if cancel was called on this task or the "exit early" flag is set then we're done
|
||||
if (isCancelled() || mExitTasksEarly) {
|
||||
@@ -377,7 +396,11 @@ public abstract class Worker {
|
||||
if (debuggable > 0) {
|
||||
Log.v(TAG, "Set ImageDrawable on: " + owner + " to: " + mUri);
|
||||
}
|
||||
owner.setBitmap(value);
|
||||
if(value instanceof Drawable){
|
||||
owner.setDrawable((Drawable) value);
|
||||
} else if(value instanceof Bitmap){
|
||||
owner.setBitmap((Bitmap) value);
|
||||
}
|
||||
}
|
||||
|
||||
if (mOnImageLoadedListener != null) {
|
||||
@@ -389,7 +412,7 @@ public abstract class Worker {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCancelled(Bitmap value) {
|
||||
protected void onCancelled(Object value) {
|
||||
super.onCancelled(value);
|
||||
synchronized (mPauseWorkLock) {
|
||||
mPauseWorkLock.notifyAll();
|
||||
Reference in New Issue
Block a user