2015-11-13 15 views
6

Gli strumenti Studio Android asset vettoriali convertire vettore disegnabile in PNG-s per i dispositivi pre-lecca ma ho davvero cattiva qualità PNG-s come si può vedere qui:Come impostare la dimensione del vettore disegnabile all'interno di un pulsante in Android?

Converted Vector to PNG

Cosa c'è di più è che il pulsante colore solido background si suppone che sia questo verde chiaro che si vede sulla sinistra, ma il drawable sovrascrivere:

<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> 

il XML per drawable è (il default dalle icone di materiale):

<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"/> 

ho voluto anche per rendere l'icona appare un po 'più piccolo modificando i valori e ho notato l'aumento delle dimensioni del riquadro di visualizzazione diminuisce l'icona, ma non sono sicuro di aver capito il motivo.

Quindi: come faccio a rendere l'icona e il PNG generato appaiono più piccoli, meno sfocati e con il colore di sfondo impostato nel file di risorse? Grazie.

EDIT: sono riuscito a ottenere il colore di sfondo solido con l'icona raggruppandole in un file XML separato con strato liste:

<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" 
    /> 

Il risultato è:

The result of some tweaking

Sono riuscito a ridurre la sfocatura aumentando la larghezza e l'altezza del vettore disegnabile. Tuttavia, senza i tag android:top|bottom|left|right, il drawable viene esteso su tutta l'area del pulsante. Il secondo pulsante non ha bisogno di avere un colore di sfondo di sfondo, quindi non sto usando i tag di elenco dei livelli => nessun modo per impostare un margine top|bottom|left|right per il drawable.
Se riduco la dimensione del pulsante, ciò che sto facendo è ridurre l'area cliccabile del pulsante.

La mia domanda aggiornata è come impostare le dimensioni del vettore disegnabile all'interno di un pulsante/pulsante di commutazione/pulsante di opzione senza ridurre le dimensioni del pulsante stesso?

UPDATE
non riuscivo a trovare un modo per ridimensionare il drawable vettoriale su pre-API 21 dispositivi. Così, invece, ho reso i pulsanti più piccoli e aumentato l'area di tocco di ciascun pulsante.

+1

Il viewport è lo spazio in cui viene disegnata l'icona e pathData fornisce le varie coordinate che indicano quale dovrebbe essere la forma. Se, ad esempio, avevi un viewport di 24 per 24 e un disegno una linea retta dal punto 0,12 al punto 24,12, allora quella è una linea orizzontale disegnata a metà strada verso il basso della tua finestra che va da un lato all'altro. Se cambi la dimensione della vista a 48 per 48 ma la tua linea è ancora dal punto 0,12 al punto 24,12, allora non inizierà più a metà e non raggiungerà l'altro lato della finestra. –

risposta

10

L'approccio corretto per ridimensionare qualsiasi drawable sarebbe utilizzare vectorDrawable.setBounds(left,top,right,bottom), ma sfortunatamente non funziona per i drawable vettoriali (perché Google?).

Quindi, come soluzione temporanea, carico i miei drawable vettoriali, li converto in bitmap drawable e ciò ci consentirà di utilizzare il metodo setBounds nel drawable bitmap. Nota che stai ridimensionando qui le bitmap, così puoi perdere un po 'di nitidezza dell'immagine. Io uso principalmente quei metodi quando ho bisogno di usare il mio drawable come un drawable composto di una vista testuale o di un pulsante per esempio.

Ho finito per scrivere una classe helper che caricherà un set vettoriale disegnabile una tinta su di esso e restituirà un disegno bitmap che puoi effettivamente ridimensionare e colorare come desideri. L'ho provato per i livelli API 19 fino a 23, e funziona.

Non dimenticare di utilizzare vectorDrawables.useSupportLibrary = true nella vostra 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; 
    } 
} 

Ora vorrei usare questa classe di supporto in questo modo:

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); 

E 'importante utilizzare un contesto di una visione o di attività, non il contesto di applicazione! Spero che risolva il tuo problema o aiuti qualcun altro. E se qualcuno ha una soluzione migliore e più pulita, sono interessato a saperlo.

0
classe

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> 

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" /> 

Nota: L'unico problema qui è un vettore non modificato (drawableWidthHeightCompatTextView didn' t use), di quale vettore è width e height sono 24,
Non è stesse dimensioni del dispositivo, con il vettore ridimensionata (di width e height sono 12 e drawableWidthHeightCompatTextView="24" vector).