2015-11-13 9 views
6

Narzędzia Android Studio Wektor Aktywa konwertować wektor rozciągliwej do PNG-ów dla urządzeń pre-Lollipop ale mam naprawdę złej jakości PNG-S, jak można zobaczyć tutaj:Jak ustawić rozmiar wektora do rysowania wewnątrz przycisku w systemie Android?

Converted Vector to PNG

Co więcej jest to, że przycisk na tło umaszczenie ma być ten jasnozielony, które można zobaczyć po lewej stronie, ale odkształcalne nadpisać go:

<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 dla rozciągliwej jest (domyślnie od materialnych ikon):

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

Chciałem też, aby ikona pojawi się nieco mniejszy od wartości szczypanie i zauważyłem zwiększenie wymiarów rzutni spada na ikonę, ale nie jestem pewien, czy rozumiem dlaczego.

Tak: Jak zrobić, aby ikona i wygenerowany PNG wyglądały na mniejsze, mniej rozmyte i z ustawionym kolorem tła w pliku zasobów? Dziękuję Ci.

EDIT: udało mi się uzyskać solidne wykształcenie kolorów z ikoną łącząc je w oddzielnym pliku XML z Layer-list:

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

wynik jest:

The result of some tweaking

Udało mi się zmniejszyć rozmycie, zwiększając szerokość i wysokość wektor drawable. Jednak bez znaczników android:top|bottom|left|right, ciągnięcie jest rozciągane na całym obszarze przycisku. Drugi przycisk nie musi mieć jednolitego koloru tła, więc nie używam tagów z listą warstw => nie ma możliwości ustawienia marginesu na rozciąganie.
Jeśli zmniejszę rozmiar przycisku, to zmniejszam klikalny obszar przycisku.

Moje zaktualizowane pytanie brzmi: jak ustawić rozmiar wektora do rysowania wewnątrz przycisku/przełącznika/przycisku radiowego bez zmniejszania samego rozmiaru przycisku?

UPDATE
nie mogłem znaleźć sposób, aby zmienić rozmiar rozciągliwej wektorowych na pre-API 21 urządzeń. Dlatego zamiast tego przyciski stały się mniejsze i zwiększono obszar dotykowy każdego przycisku.

+1

Widoczna to przestrzeń, w której rysowana jest ikona, a pathData podaje różne współrzędne określające kształt. Jeśli, na przykład, miałeś widok z 24 na 24 i narysowałeś jedną linię prostą od punktu 0,12 do punktu 24,12, to jest to pozioma linia narysowana w połowie ekranu, przechodząca z jednej strony z prawej strony na drugą. Jeśli zmienisz rozmiar widocznego obszaru na 48 przez 48, ale twoja linia nadal będzie się wahać od punktu 0,12 do punktu 24,12, to nie zacznie ona już więcej niż w połowie i nie osiągnie drugiej strony widoku. –

Odpowiedz

10

Prawidłowym podejściem do skalowania każdego losowania byłoby użycie vectorDrawable.setBounds(left,top,right,bottom), , ale niestety to nie działa w przypadku wektorów (dlaczego Google?).

W ramach obejścia ładuję moje rysunki wektorowe, konwertuję je na rysunki bitmapowe, które pozwolą nam użyć metody setBounds w losowaniu bitmapy. Zwróć uwagę, że skalujesz bitmapy tutaj, więc możesz utracić ostrość obrazu. Używam głównie tych metod, gdy potrzebuję użyć mojego drawable jako złożonego ciągnięcia widoku tekstowego lub przycisku na przykład.

Skończyło się na napisaniu klasy pomocnika, która załaduje zestaw do rysowania wektorowego i zabarwi go i zwróci mapę bitową, którą można w rzeczywistości skalować i przyciemniać. Przetestowałem go na poziomie API od 19 do 23 i działa.

Nie zapomnij użyć vectorDrawables.useSupportLibrary = true w 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; 
    } 
} 

Teraz chciałbym skorzystać z tej klasy pomocnika tak:

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

Ważne jest, aby używać kontekście View lub działalności, a nie kontekst aplikacji! Mam nadzieję, że rozwiąże on Twój problem lub pomoże komuś innemu. A jeśli ktoś ma lepsze i czystsze rozwiązanie, również mnie to interesuje.

0
klasa

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> 

Zastosowanie:

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

Uwaga: Jedynym problemem tutaj jest niemodyfikowana wektor (drawableWidthHeightCompatTextView nie zrobił” t use), które to są width i height są 24
nie Czy równe pod względem wielkości na urządzeniu, z wektora zmienionym rozmiarze (VECTOR width i height są 12 i drawableWidthHeightCompatTextView="24").

Powiązane problemy