The Android Studio Vector Assets tools convert vector drawable to PNG-s for devices pre-Lollipop but I get really bad quality PNG-s as you can see here:
What's more is that the button's background solid color is supposed to be this light green that you see on the left but the drawable overwrite it:
<item android:state_checked="true"
android:drawable="@drawable/show">
<shape android:shape="rectangle">
<corners android:bottomRightRadius="8dp"/>
<solid android:color="@color/waveComponentGreen"/>
</shape>
</item>
<item android:state_checked="false"
android:drawable="@drawable/hide">
<shape android:shape="rectangle">
<corners android:bottomRightRadius="8dp"/>
<solid android:color="@color/waveComponentGreen"/>
</shape>
</item>
The xml for the drawable is (the default from the material icons):
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M8.59,16.34l4.58,-4.59 -4.58,-4.59L10,5.75l6,6 -6,6z"/>
I wanted also to make the icon appear a bit smaller by tweaking the values and I noticed increasing the viewport dimensions decreases the icon but I'm not sure I understand why.
So: How do I make the icon and the generated PNG appear smaller, less blurry and with the background colour set in the resource file? Thank you.
EDIT : I managed to get the solid colour background with the icon by combining them in a separate xml file with layer-lists:
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
<shape android:shape="rectangle">
<corners android:bottomRightRadius="10dp"/>
<solid android:color="@color/waveComponentGreen"/>
</shape>
</item>
<item android:drawable="@drawable/show"
android:top="10dp"
android:bottom="10dp"
android:left="10dp"
android:right="10dp"
/>
The result is:
I managed to reduce the blurring by increasing the width and height of the vector drawable. However without the android:top|bottom|left|right
tags, the drawable is stretched across the whole area of the button. The second button doesn't need to have a background solid color so I'm not using the layer-list tags => no way to set a top|bottom|left|right
margin for the drawable.
If I reduce the button size what I'm doing is reducing the clickable area of the button.
My updated question is how to set the size of the vector drawable inside a button/toggle button/radio button without reducing the size of the button itself?
UPDATE
I couldn't find a way to resize the vector drawable on pre-API 21 devices. So instead I made the buttons themselves smaller and increased the touch area of each button.
The correct approach to scale any drawable would be to use vectorDrawable.setBounds(left,top,right,bottom)
, but unfortunately that does not work for vector drawables (why Google ?).
So as a workaround I load my vector drawables , convert them to bitmap drawable and that will allow us to use the setBounds
method on the bitmap drawable. Note that you are scaling bitmaps here , so you can lose some sharpness of the image. I mainly use those methods when I need to use my drawable as a compound drawable of a text view or a button for example.
I ended up writing a helper class that will load a vector drawable set a tint to it and return a bitmap drawable that you can actually scale and tint as you wish. I've tested it for API levels 19 up to 23 , and it works.
Don't forget to use vectorDrawables.useSupportLibrary = true
in your build.gradle .
public class VectorDrawableUtils {
/**
* Gets a Bitmap from provided Vector Drawable image
*
* @param vd VectorDrawable
* @return Bitmap
*/
public static Optional<Bitmap> createBitmapFromVectorDrawable(final @NonNull Drawable vd) {
try {
Bitmap bitmap;
bitmap = Bitmap.createBitmap(vd.getIntrinsicWidth(), vd.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
vd.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
vd.draw(canvas);
return Optional.of(bitmap);
} catch (OutOfMemoryError e) {
Injector.getDependency(getContext(), IEventTracker.class).logHandledException(e);
return Optional.empty();
}
}
/**
* Loads vector drawable and apply tint color on it.
*/
public static Drawable loadVectorDrawableWithTintColor(final @DrawableRes int vdRes,
final @ColorRes int clrRes,final Context context) {
Drawable drawable = ContextCompat.getDrawable(context, vdRes);
DrawableCompat.setTint(drawable, getContext().getResources().getColor(clrRes));
return drawable;
}
/**
* Converts given vector drawable to Bitmap drawable
*/
public static BitmapDrawable convertVectorDrawableToBitmapDrawable(final @NonNull Drawable vd) {
//it is safe to create empty bitmap drawable from null source
return new BitmapDrawable(createBitmapFromVectorDrawable(vd).get());
}
/**
* Loads vector drawable , aplys tint on it and returns a wrapped bitmap drawable.
* Bitmap drawable can be resized using setBounds method (unlike the VectorDrawable)
* @param context Requires view context !
*/
public static Drawable loadVectorDrawableWithTint(
final @DrawableRes int vectorDrawableRes, final @ColorRes int colorRes,final Context context) {
Drawable vd = VectorDrawableUtils.loadVectorDrawableWithTintColor(vectorDrawableRes,
colorRes, context);
final BitmapDrawable bitmapDrawable = VectorDrawableUtils.convertVectorDrawableToBitmapDrawable(vd);
ColorStateList tint = ContextCompat.getColorStateList(context,colorRes);
final Drawable wrappedDrawable = DrawableCompat.wrap(bitmapDrawable);
DrawableCompat.setTintList(wrappedDrawable,tint);
return wrappedDrawable;
}
}
Now I would use this helper class like this :
Drawable bd = VectorDrawableUtils.loadVectorDrawableWithTint(
R.drawable.ic_dropdown, R.color.black,getContext());
bd.setBounds(0, 0, textView.getMeasuredHeight(), textView.getMeasuredHeight());
textView.setCompoundDrawablesWithIntrinsicBounds(null, null, bd, null);
It is important to use a Context of a View or Activity, not the Application context! Hope it will solve your problem, or help someone else. And if someone has a better and cleaner solution, I am interested to know as well.
MyTextView class:
public class MyTextView extends AppCompatTextView {
public MyTextView(Context context) {
super(context);
}
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
initAttrs(context, attrs);
}
public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initAttrs(context, attrs);
}
void initAttrs(Context context, AttributeSet attrs) {
if (attrs != null) {
TypedArray attributeArray = context.obtainStyledAttributes(
attrs,
R.styleable.MyTextView);
int defaultWidthHeight = 0;
int widthHeight = 0;
Drawable drawableLeft = null;
Drawable drawableStart = null;
Drawable drawableRight = null;
Drawable drawableEnd = null;
Drawable drawableBottom = null;
Drawable drawableTop = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
drawableLeft = attributeArray.getDrawable(R.styleable.MyTextView_drawableLeftCompatTextView);
drawableStart = attributeArray.getDrawable(R.styleable.MyTextView_drawableStartCompatTextView);
drawableRight = attributeArray.getDrawable(R.styleable.MyTextView_drawableRightCompatTextView);
drawableEnd = attributeArray.getDrawable(R.styleable.MyTextView_drawableEndCompatTextView);
drawableBottom = attributeArray.getDrawable(R.styleable.MyTextView_drawableBottomCompatTextView);
drawableTop = attributeArray.getDrawable(R.styleable.MyTextView_drawableTopCompatTextView);
} else {
final int drawableLeftId = attributeArray.getResourceId(R.styleable.MyTextView_drawableLeftCompatTextView, -1);
final int drawableStartId = attributeArray.getResourceId(R.styleable.MyTextView_drawableStartCompatTextView, -1);
final int drawableRightId = attributeArray.getResourceId(R.styleable.MyTextView_drawableRightCompatTextView, -1);
final int drawableEndId = attributeArray.getResourceId(R.styleable.MyTextView_drawableEndCompatTextView, -1);
final int drawableBottomId = attributeArray.getResourceId(R.styleable.MyTextView_drawableBottomCompatTextView, -1);
final int drawableTopId = attributeArray.getResourceId(R.styleable.MyTextView_drawableTopCompatTextView, -1);
if (drawableLeftId != -1)
drawableLeft = AppCompatResources.getDrawable(context, drawableLeftId);
if(drawableStartId != -1)
drawableStart = AppCompatResources.getDrawable(context, drawableStartId);
if (drawableRightId != -1)
drawableRight = AppCompatResources.getDrawable(context, drawableRightId);
if(drawableEndId != -1)
drawableEnd = AppCompatResources.getDrawable(context, drawableEndId);
if (drawableBottomId != -1)
drawableBottom = AppCompatResources.getDrawable(context, drawableBottomId);
if (drawableTopId != -1)
drawableTop = AppCompatResources.getDrawable(context, drawableTopId);
}
if(!attributeArray.hasValue(R.styleable.MyTextView_drawableWidthHeightCompatTextView)) {
if (attributeArray.hasValue(R.styleable.MyTextView_drawableLeftCompatTextView)) {
defaultWidthHeight = drawableLeft.getIntrinsicWidth();
} else if (attributeArray.hasValue(R.styleable.MyTextView_drawableStartCompatTextView)) {
defaultWidthHeight = drawableStart.getIntrinsicWidth();
} else if (attributeArray.hasValue(R.styleable.MyTextView_drawableRightCompatTextView)) {
defaultWidthHeight = drawableRight.getIntrinsicWidth();
} else if (attributeArray.hasValue(R.styleable.MyTextView_drawableEndCompatTextView)) {
defaultWidthHeight = drawableEnd.getIntrinsicWidth();
} else if (attributeArray.hasValue(R.styleable.MyTextView_drawableBottomCompatTextView)) {
defaultWidthHeight = drawableBottom.getIntrinsicWidth();
} else if (attributeArray.hasValue(R.styleable.MyTextView_drawableTopCompatTextView)) {
defaultWidthHeight = drawableTop.getIntrinsicWidth();
}
widthHeight = attributeArray.getInt(R.styleable.MyTextView_drawableWidthHeightCompatTextView, defaultWidthHeight);
} else
widthHeight = attributeArray.getInt(R.styleable.MyTextView_drawableWidthHeightCompatTextView, defaultWidthHeight);
if(attributeArray.hasValue(R.styleable.MyTextView_drawableColorCompatTextView)){
ColorStateList tintColor = attributeArray.getColorStateList(R.styleable.MyTextView_drawableColorCompatTextView);
if (attributeArray.hasValue(R.styleable.MyTextView_drawableLeftCompatTextView)) {
//drawableLeft.setColorFilter(new PorterDuffColorFilter(tintColor.getDefaultColor(), PorterDuff.Mode.MULTIPLY));
DrawableCompat.setTintList(drawableLeft, tintColor);
} else if (attributeArray.hasValue(R.styleable.MyTextView_drawableStartCompatTextView)) {
//drawableStart.setColorFilter(new PorterDuffColorFilter(tintColor.getDefaultColor(), PorterDuff.Mode.MULTIPLY));
DrawableCompat.setTintList(drawableStart, tintColor);
} else if (attributeArray.hasValue(R.styleable.MyTextView_drawableRightCompatTextView)) {
//drawableRight.setColorFilter(new PorterDuffColorFilter(tintColor.getDefaultColor(), PorterDuff.Mode.MULTIPLY));
DrawableCompat.setTintList(drawableRight, tintColor);
} else if (attributeArray.hasValue(R.styleable.MyTextView_drawableEndCompatTextView)) {
//drawableEnd.setColorFilter(new PorterDuffColorFilter(tintColor.getDefaultColor(), PorterDuff.Mode.MULTIPLY));
DrawableCompat.setTintList(drawableEnd, tintColor);
} else if (attributeArray.hasValue(R.styleable.MyTextView_drawableBottomCompatTextView)) {
//drawableBottom.setColorFilter(new PorterDuffColorFilter(tintColor.getDefaultColor(), PorterDuff.Mode.MULTIPLY));
DrawableCompat.setTintList(drawableBottom, tintColor);
} else if (attributeArray.hasValue(R.styleable.MyTextView_drawableTopCompatTextView)) {
//drawableTop.setColorFilter(new PorterDuffColorFilter(tintColor.getDefaultColor(), PorterDuff.Mode.MULTIPLY));
DrawableCompat.setTintList(drawableTop, tintColor);
}
}
WrappedDrawable drawableLeftWrapped = new WrappedDrawable(drawableLeft);
drawableLeftWrapped.setBounds(0, 0, widthHeight, widthHeight);
WrappedDrawable drawableStartWrapped = new WrappedDrawable(drawableStart);
drawableStartWrapped.setBounds(0, 0, widthHeight, widthHeight);
WrappedDrawable drawableRightWrapped = new WrappedDrawable(drawableRight);
drawableRightWrapped.setBounds(0, 0, widthHeight, widthHeight);
WrappedDrawable drawableEndWrapped = new WrappedDrawable(drawableEnd);
drawableEndWrapped.setBounds(0, 0, widthHeight, widthHeight);
WrappedDrawable drawableBottomWrapped = new WrappedDrawable(drawableBottom);
drawableBottomWrapped.setBounds(0, 0, widthHeight, widthHeight);
WrappedDrawable drawableTopWrapped = new WrappedDrawable(drawableTop);
drawableTopWrapped.setBounds(0, 0, widthHeight, widthHeight);
setCompoundDrawablesWithIntrinsicBounds(drawableLeftWrapped, drawableTopWrapped, drawableRightWrapped, drawableBottomWrapped);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
setCompoundDrawablesRelativeWithIntrinsicBounds(drawableStartWrapped, drawableTopWrapped, drawableEndWrapped, drawableBottomWrapped);
attributeArray.recycle();
}
}
class WrappedDrawable extends Drawable {
private final Drawable _drawable;
protected Drawable getDrawable() {
return _drawable;
}
public WrappedDrawable(Drawable drawable) {
super();
_drawable = drawable;
}
@Override
public void setBounds(int left, int top, int right, int bottom) {
//update bounds to get correctly
super.setBounds(left, top, right, bottom);
Drawable drawable = getDrawable();
if (drawable != null) {
drawable.setBounds(left, top, right, bottom);
}
}
@Override
public void setAlpha(int alpha) {
Drawable drawable = getDrawable();
if (drawable != null) {
drawable.setAlpha(alpha);
}
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
Drawable drawable = getDrawable();
if (drawable != null) {
drawable.setColorFilter(colorFilter);
}
}
@Override
public int getOpacity() {
Drawable drawable = getDrawable();
return drawable != null
? drawable.getOpacity()
: PixelFormat.UNKNOWN;
}
@Override
public void draw(Canvas canvas) {
Drawable drawable = getDrawable();
if (drawable != null) {
drawable.draw(canvas);
}
}
@Override
public int getIntrinsicWidth() {
Drawable drawable = getDrawable();
return drawable != null
? drawable.getBounds().width()
: 0;
}
@Override
public int getIntrinsicHeight() {
Drawable drawable = getDrawable();
return drawable != null ?
drawable.getBounds().height()
: 0;
}
}
}
attrs.xml:
<declare-styleable name="MyTextView">
<attr name="drawableColorCompatTextView" format="reference|color"/>
<attr name="drawableWidthHeightCompatTextView" format="integer"/>
<attr name="drawableLeftCompatTextView" format="reference"/>
<attr name="drawableStartCompatTextView" format="reference"/>
<attr name="drawableRightCompatTextView" format="reference"/>
<attr name="drawableEndCompatTextView" format="reference"/>
<attr name="drawableTopCompatTextView" format="reference"/>
<attr name="drawableBottomCompatTextView" format="reference"/>
</declare-styleable>
Usage:
<com.packagename.MyTextView
android:id="@+id/txtUserName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:drawableLeftCompatTextView="@drawable/ic_username"
app:drawableStartCompatTextView="@drawable/ic_username"
app:drawableWidthHeightCompatTextView="48"
app:drawableColorCompatTextView="@color/blue" />
Note: The only issue here is an unmodified vector( drawableWidthHeightCompatTextView
didn't use), which vector's width
and height
are 24,
Is not equal in size on the device, with resized vector(vector's width
and height
are 12 and drawableWidthHeightCompatTextView="24"
).
look at this I found, it works in Vector and regular Drawables! I think it is the shortest solution I saw.
The idea is to create a custom drawable with fixed intrinsic size and pass the drawing job on to the original drawable.
final Drawable d = container.getContext().getDrawable(R.drawable.your_drawable);
Drawable icon = new ColorDrawable(){
Drawable iconOrig = d;
@Override
public void setBounds(int left, int top, int right, int bottom){
super.setBounds(left, top, right, bottom);//This is needed so that getBounds on this class would work correctly.
iconOrig.setBounds(left, top, right, bottom);
}
@Override
public void draw(Canvas canvas){
iconOrig.draw(canvas);
}
@Override
public int getIntrinsicWidth(){
return 27;//the width you want
}
@Override
public int getIntrinsicHeight(){
return 19;// the height you want
}
};
I used a FrameLayout
to put an ImageButton
and an ImageView
together and to be able to resize the ImageView
:
<FrameLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="60dp"
android:layout_height="60dp"
>
<ImageButton
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center"
app:srcCompat="@drawable/baseline_arrow_right_24"
/>
</FrameLayout>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.