Android Studio Vector Assetsツールは、ロリポップ以前のデバイスのベクタードローアブルをPNG-sに変換しますが、ここに表示されているように、非常に質の悪いPNG-sを取得します。
さらに、ボタンの背景の単色は、左側に表示されているこの薄緑色であるはずですが、ドローアブルがそれを上書きします。
<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>
ドローアブルのxmlは(マテリアルアイコンのデフォルト)です。
<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"/>
また、値を微調整してアイコンを少し小さく表示したかったので、ビューポートのサイズを大きくするとアイコンが小さくなることに気付きましたが、その理由がわかりません。
だから:アイコンと生成されたPNGをより小さく、ぼやけにくく、リソースファイルで設定された背景色で表示するにはどうすればよいですか?ありがとうございました。
[〜#〜] edit [〜#〜]:別のxmlファイルでそれらを組み合わせることにより、アイコンと単色の背景を取得することができました。レイヤーリスト:
<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"
/>
結果は次のとおりです。
ベクトルドローアブルの幅と高さを増やすことで、ぼやけを減らすことができました。ただし、Android:top|bottom|left|right
タグがないと、ドローアブルはボタンの領域全体に広がります。 2番目のボタンは背景の単色である必要がないため、レイヤーリストタグを使用していません=>ドローアブルにtop|bottom|left|right
マージンを設定する方法はありません。
ボタンのサイズを小さくすると、ボタンのクリック可能な領域が小さくなります。
私の更新された質問は、ボタン自体のサイズを縮小せずに、ボタン/トグルボタン/ラジオボタン内に描画可能なベクトルのサイズを設定する方法です。
[〜#〜]更新[〜#〜]
API21より前のデバイスで描画可能なベクターのサイズを変更する方法が見つかりませんでした。そこで、代わりにボタン自体を小さくし、各ボタンのタッチ領域を増やしました。
ドローアブルをスケーリングする正しいアプローチはvectorDrawable.setBounds(left,top,right,bottom)
を使用することですが、残念ながらそれはベクタードローアブルでは機能しません(なぜGoogle?)。
したがって、回避策として、ベクタードローアブルをロードし、ビットマップドローアブルに変換します。これにより、ビットマップドローアブルでsetBounds
メソッドを使用できるようになります。ここではビットマップをスケーリングしているため、画像の鮮明さが失われる可能性があることに注意してください。私は主に、ドローアブルをテキストビューやボタンなどの複合ドローアブルとして使用する必要がある場合にこれらのメソッドを使用します。
結局、ベクタードローアブルをロードして色合いを設定し、実際に必要に応じて拡大縮小して色合いを付けることができるビットマップドローアブルを返すヘルパークラスを作成することになりました。 APIレベル19から23までテストしましたが、機能します。
build.gradleでvectorDrawables.useSupportLibrary = true
を使用することを忘れないでください。
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;
}
}
今、私はこのようなヘルパークラスを使用します:
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);
アプリケーションコンテキストではなく、ビューまたはアクティビティのコンテキストを使用することが重要です。それがあなたの問題を解決するか、他の誰かを助けることを願っています。そして、誰かがより良い、よりクリーンな解決策を持っているなら、私も知りたいです。
MyTextViewクラス:
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>
使用法:
<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" />
注:ここでの唯一の問題は、変更されていないベクトル(drawableWidthHeightCompatTextView
は使用しませんでした)です。このベクトルのwidth
とheight
は24です、
そうではありませんデバイスのサイズが同じで、サイズが変更されたベクトル(ベクトルのwidth
とheight
は12とdrawableWidthHeightCompatTextView="24"
)。