1. drawable资源文件问题汇总
1.1.1. Android 6 不支持 gradient with offset
Caused by org.xmlpull.v1.XmlPullParserException
Binary XML file line #7: invalid color state list tag gradient
android.content.res.ColorStateList.createFromXmlInner + 217 (ColorStateList.java:217)
android.view.LayoutInflater.createView + 619 (LayoutInflater.java:619)
比如下面的一个vector文件,在Android 6 系统中就会导致crash。
<vector android:height="22dp" android:viewportHeight="156.896"
android:viewportWidth="156.897" android:width="22dp"
xmlns:aapt="http://schemas.android.com/aapt" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#fff" android:pathData="M152.456, 93.734Z"/>
<path android:pathData="M122.095,0.003L34.79">
<aapt:attr name="android:fillColor">
<gradient android:endX="87.7021" android:endY="87.7101"
android:startX="13.802198" android:startY="13.810199" android:type="linear">
<item android:color="#FFFF321E" android:offset="0"/>
<item android:color="#FFED171F" android:offset="1"/>
</gradient>
</aapt:attr>
</path>
</vector>
this is because you use a few attributes not supported prior to API level 24.
eg. startX, endX, startY, endY and offset.
Android Marshmallow 6.0 is API level 23 ...
that invalid color state list tag gradient is coming from the offset:
<item android:color="#FF2AF598" android:offset="0"/>
<item android:color="#FF009EFD" android:offset="1"/>
this issue most likely isn't LG specific, but Marshmallow specific.
1.1.2. Android 6 AnimatedVectorDrawable NPE
如下一个vector资源文件
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="14dp"
android:height="14dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#797872"
android:pathData="M11,17h2v-6h-2v6zM12" />
</vector>
当使用AnimatedVectorDrawable去加载它时,会引发NullPointerException。
The crash happens when I try to launch the animation on an AnimatedVectorDrawable which has NO target attribute (I'm using a single XML file to define the vector drawable and its animations).
More precisely, I think android looks into the animated-vector element and throws an error if no target found.
I can only think of two solutions for now:
- either add at least one
targetelement into theAnimatedVectorDrawable, - or use a simple
VectorDrawableif no animation is needed (I usedAnimatedVectorDrawableregardless whether or not my vector was animated, to be able to easily add animations to it later if I wanted to).
I found a simple workaround to avoid changing everything, that maybe can help others: I just had to add a dumb target to all my AnimatedVectorDrawable that shouldn't be animated.
<target android:name="vector">
<aapt:attr name="android:animation">
<objectAnimator
android:propertyName="alpha"
android:valueTo="1"/>
</aapt:attr>
</target>
修改上面的vector文件:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<animated-vector xmlns:aapt="http://schemas.android.com/aapt"
xmlns:android="http://schemas.android.com/apk/res/android">
<aapt:attr name="android:drawable">
<vector
android:width="14dp"
android:height="14dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#797872"
android:pathData="M11,17h2v-6h-2v6zM12" />
</vector>
</aapt:attr>
</animated-vector>
1.1.3. vector资源文件转换Bitmap
public static Bitmap getBitmapFromVectorDrawable(Context context, int drawableId) {
Drawable drawable = ContextCompat.getDrawable(context, drawableId);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
drawable = (DrawableCompat.wrap(drawable)).mutate();
}
Bitmap bitmap = Bitmap.createBitmap(48, 48, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
try {
saveBitmap(bitmap, Environment.getExternalStorageDirectory());
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
private static void saveBitmap(Bitmap bitmap, File file) throws IOException {
//create a file to write bitmap data
File f = new File(file, "xx.png");
f.createNewFile();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 0 /*ignored for PNG*/, bos);
byte[] bitmapdata = bos.toByteArray();
FileOutputStream fos = new FileOutputStream(f);
fos.write(bitmapdata);
fos.flush();
fos.close();
}