Czy można używać VectorDrawable w Buttons i TextViews przy użyciu Androida: DrawableRight?

120

Kiedy używam zasobów VectorDrawable w widoku tekstowym lub widoku obrazu, podczas korzystania z funkcji „android: DrawableRight” / „android: DrawableEnd” / „android: DrawableStart” / „android: DrawableLeft” występuje awaria środowiska wykonawczego.

Aplikacja skompiluje się bez żadnych ostrzeżeń.

ja używam

  • Gradle 1.5
  • Obsługa biblioteki 23.2 ('com.android.support:appcompat-v7:23.2.0')

Odkryłem jednak, że mogę programowo przypisać pliki SVG w Javie bez takich awarii.

TextView tv = (TextView) findViewById(R.id.textView);
tv.setCompoundDrawablesWithIntrinsicBounds(null,null, getResources().getDrawable(R.drawable.ic_accessible_white_36px),null);

(Podejrzewam, że jest to błąd biblioteki obsługi wersji 23.2.)

Ale czy można użyć drawableRight itp. Do zasobów SVG?

Oto mój układ

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="au.com.angryitguy.testsvg.MainActivity">


<TextView
    android:id="@+id/textView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:drawableRight="@drawable/ic_accessible_white_36px"
    android:background="@color/colorPrimary"
    android:textColor="#FFFFFF"
    android:textSize="22sp"
    android:text="Hello World!"/>
</RelativeLayout>

Oto moja aktywność

package au.com.angryitguy.testsvg;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        }
    }

Oto niezmodyfikowany zasób VectorDrawable z witryny Google Material Design.

<vector android:height="24dp" android:viewportHeight="24.0"
    android:viewportWidth="24.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
    <path android:fillColor="#FFFFFF" android:pathData="M12,4m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
    <path android:fillColor="#FFFFFF" android:pathData="M19,13v-2c-1.54,0.02 -3.09,-0.75 -4.07,-1.83l-1.29,-1.43c-0.17,-0.19 -0.38,-0.34 -0.61,-0.45 -0.01,0 -0.01,-0.01 -0.02,-0.01L13,7.28c-0.35,-0.2 -0.75,-0.3 -1.19,-0.26C10.76,7.11 10,8.04 10,9.09L10,15c0,1.1 0.9,2 2,2h5v5h2v-5.5c0,-1.1 -0.9,-2 -2,-2h-3v-3.45c1.29,1.07 3.25,1.94 5,1.95zM12.83,18c-0.41,1.16 -1.52,2 -2.83,2 -1.66,0 -3,-1.34 -3,-3 0,-1.31 0.84,-2.41 2,-2.83L9,12.1c-2.28,0.46 -4,2.48 -4,4.9 0,2.76 2.24,5 5,5 2.42,0 4.44,-1.72 4.9,-4h-2.07z"/>
</vector>

Oto moja aplikacja build.gradle

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig {
        applicationId "au.com.angryitguy.testsvg"
        minSdkVersion 16
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
        // Stops the Gradle plugin’s automatic rasterization of vectors
        generatedDensities = []
    }
    // Flag to tell aapt to keep the attribute ids around
    aaptOptions {
        additionalParameters "--no-version-vectors"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.2.0'
}

Oto katastrofa. (Zwróć uwagę na błędy inflacji, które odnoszą się do widoku tekstowego).

java.lang.RuntimeException: Unable to start activity ComponentInfo{
    au.com.angryitguy.testsvg/au.com.angryitguy.testsvg.MainActivity}: 
    android.view.InflateException: Binary XML file line #13: 
    Error inflating class TextView

at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2059)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
at android.app.ActivityThread.access$600(ActivityThread.java:130)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4745)
...

Caused by: android.view.InflateException: 
    Binary XML file line #13: Error inflating class TextView
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:704)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:746)
at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
at android.view.LayoutInflater.inflate(LayoutInflater.java:352)
at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:267)
at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:129)
at au.com.angryitguy.testsvg.MainActivity.onCreate(MainActivity.java:14)
at android.app.Activity.performCreate(Activity.java:5008)
...

Caused by: android.content.res.Resources$NotFoundException: 
    File res/drawable/ic_accessible_white_36px.xml from drawable resource ID #0x7f02004b
at android.content.res.Resources.loadDrawable(Resources.java:1918)
at android.content.res.TypedArray.getDrawable(TypedArray.java:601)
at android.widget.TextView.<init>(TextView.java:622)
at android.support.v7.widget.AppCompatTextView.<init>(AppCompatTextView.java:60)
at android.support.v7.widget.AppCompatTextView.<init>(AppCompatTextView.java:56)
at android.support.v7.app.AppCompatViewInflater.createView(AppCompatViewInflater.java:103)
at android.support.v7.app.AppCompatDelegateImplV7.createView(AppCompatDelegateImplV7.java:963)
at android.support.v7.app.AppCompatDelegateImplV7.onCreateView(AppCompatDelegateImplV7.java:1022)
at android.support.v4.view.LayoutInflaterCompatHC$FactoryWrapperHC.onCreateView(LayoutInflaterCompatHC.java:44)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:675)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:746) 
at android.view.LayoutInflater.inflate(LayoutInflater.java:489) 
at android.view.LayoutInflater.inflate(LayoutInflater.java:396) 
at android.view.LayoutInflater.inflate(LayoutInflater.java:352) 
at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:267) 
at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:129) 
at au.com.angryitguy.testsvg.MainActivity.onCreate(MainActivity.java:14) 
at android.app.Activity.performCreate(Activity.java:5008) 
...

Caused by: org.xmlpull.v1.XmlPullParserException:
    Binary XML file line #1: invalid drawable tag vector
at android.graphics.drawable.Drawable.createFromXmlInner(Drawable.java:877)
at android.graphics.drawable.Drawable.createFromXml(Drawable.java:818)
at android.content.res.Resources.loadDrawable(Resources.java:1915)
at android.content.res.TypedArray.getDrawable(TypedArray.java:601) 
at android.widget.TextView.<init>(TextView.java:622) 
at android.support.v7.widget.AppCompatTextView.<init>(AppCompatTextView.java:60) 
at android.support.v7.widget.AppCompatTextView.<init>(AppCompatTextView.java:56) 
at android.support.v7.app.AppCompatViewInflater.createView(AppCompatViewInflater.java:103) 
at android.support.v7.app.AppCompatDelegateImplV7.createView(AppCompatDelegateImplV7.java:963) 
at android.support.v7.app.AppCompatDelegateImplV7.onCreateView(AppCompatDelegateImplV7.java:1022) 
at android.support.v4.view.LayoutInflaterCompatHC$FactoryWrapperHC.onCreateView(LayoutInflaterCompatHC.java:44) 
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:675) 
at android.view.LayoutInflater.rInflate(LayoutInflater.java:746) 
at android.view.LayoutInflater.inflate(LayoutInflater.java:489) 
at android.view.LayoutInflater.inflate(LayoutInflater.java:396) 
at android.view.LayoutInflater.inflate(LayoutInflater.java:352) 
at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:267) 
at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:129) 
at au.com.angryitguy.testsvg.MainActivity.onCreate(MainActivity.java:14) 
at android.app.Activity.performCreate(Activity.java:5008) 
...
angryITguy
źródło
Nie, nie możesz, ponieważ pliki SVG nie są obsługiwane natywnie . Zamiast tego musisz użyć VectorDrawable (który wykorzystuje tylko podzbiór specyfikacji SVG).
Phantômaxx
2
Aby zobaczyć, jak używać VectorDrawable with drawableLeft, drawableRight, drawableTop, drawableBottom sprawdź tę odpowiedź
Behzad Bahmanyar
Znalazłem to działa dla mnie: android.jlelse.eu/…
Huy Tower

Odpowiedzi:

186

czy można używać drawableRight itp. dla zasobów SVG?

tak

AppCompatTextView się wsporniki app:drawableLeftCompat, app:drawableTopCompat, app:drawableRightCompat, app:drawableBottomCompat, app:drawableStartCompati app:drawableEndCompatkanału alfa związek, wspierając przeniesione rozciągliwej typów, takich jak VectorDrawableCompat.

Uwzględnij to w swoim pliku gradle

implementation 'androidx.appcompat:appcompat:1.1.0-alpha01'

W widoku tekstu możesz użyć

app:drawableLeftCompat
app:drawableStartCompat

Jeśli masz problemy podczas korzystania z app: drawableLeftCompat, app: drawableStartCompat w przyciskach, musisz zaktualizować swoją bibliotekę do

androidx.appcompat: appcompat: 1.2.0-alpha01

mieli włączony błąd

androidx.appcompat: appcompat: 1.1.0-alpha01

możesz zobaczyć dokumenty


A jeśli nie chcesz jeszcze aktualizować, to:

Ponieważ wydaje się, że Google w najbliższym czasie nie zrobi nic w tej sprawie, musiałem wymyślić solidniejsze rozwiązanie wielokrotnego użytku dla wszystkich moich aplikacji:

  1. Pierwszy dodatek zwyczaj TextView atrybutów pliku w attrs.xml swojej aplikacji „RES / wartości / attrs.xml” :

    <resources>
        <declare-styleable name="CustomTextView">
            <attr name="drawableStartCompat" format="reference"/>
            <attr name="drawableEndCompat" format="reference"/>
            <attr name="drawableTopCompat" format="reference"/>
            <attr name="drawableBottomCompat" format="reference"/>
        </declare-styleable>
    </resources>
  2. Następnie utwórz niestandardową klasę TextView w następujący sposób:

    import android.content.Context;
    import android.content.res.TypedArray;
    import android.graphics.drawable.Drawable;
    import android.os.Build;
    import android.support.v7.content.res.AppCompatResources;
    import android.support.v7.widget.AppCompatTextView;
    import android.util.AttributeSet;
    
    public class CustomTextView extends AppCompatTextView {
        public CustomTextView(Context context) {
            super(context);
        }    
        public CustomTextView(Context context, AttributeSet attrs) {
            super(context, attrs);
            initAttrs(context, attrs);
        }
        public CustomTextView(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.CustomTextView);
    
                Drawable drawableStart = null;
                Drawable drawableEnd = null;
                Drawable drawableBottom = null;
                Drawable drawableTop = null;
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    drawableStart = attributeArray.getDrawable(R.styleable.CustomTextView_drawableStartCompat);
                    drawableEnd = attributeArray.getDrawable(R.styleable.CustomTextView_drawableEndCompat);
                    drawableBottom = attributeArray.getDrawable(R.styleable.CustomTextView_drawableBottomCompat);
                    drawableTop = attributeArray.getDrawable(R.styleable.CustomTextView_drawableTopCompat);
                } else {
                    final int drawableStartId = attributeArray.getResourceId(R.styleable.CustomTextView_drawableStartCompat, -1);
                    final int drawableEndId = attributeArray.getResourceId(R.styleable.CustomTextView_drawableEndCompat, -1);
                    final int drawableBottomId = attributeArray.getResourceId(R.styleable.CustomTextView_drawableBottomCompat, -1);
                    final int drawableTopId = attributeArray.getResourceId(R.styleable.CustomTextView_drawableTopCompat, -1);
    
                    if (drawableStartId != -1)
                        drawableStart = AppCompatResources.getDrawable(context, drawableStartId);
                    if (drawableEndId != -1)
                        drawableEnd = AppCompatResources.getDrawable(context, drawableEndId);
                    if (drawableBottomId != -1)
                        drawableBottom = AppCompatResources.getDrawable(context, drawableBottomId);
                    if (drawableTopId != -1)
                        drawableTop = AppCompatResources.getDrawable(context, drawableTopId);
                }
    
                // to support rtl
                setCompoundDrawablesRelativeWithIntrinsicBounds(drawableStart, drawableTop, drawableEnd, drawableBottom);
                attributeArray.recycle();
            }
        }
    }
  3. Teraz możesz go łatwo używać w dowolnych układach według własnych atrybutów:

    <YOUR_VIEW_PACKAGE.CustomTextView
        android:id="@+id/edt_my_edit_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:drawableStartCompat="@drawable/your_vector_drawable" <!-- vector drawable -->
        app:drawableEndCompat="@drawable/your_vector_drawable" <!-- vector drawable -->
        app:drawableTopCompat="@drawable/your_vector_drawable" <!-- vector drawable -->
        app:drawableBottomCompat="@drawable/your_vector_drawable" <!-- vector drawable -->
        />
    • Możesz zrobić podobną rzecz z Button , EditText i RadioButton, ponieważ pochodzą one z TextView

Mam nadzieję że to pomoże :)

Behzad Bahmanyar
źródło
4
Bardzo przydatna odpowiedź. W każdym razie polecam również przeczytanie bardzo wyczerpującej odpowiedzi Dadou . Usunięcie vectorDrawables { useSupportLibrary = true }z mojego, build.gradlejak sugeruje ta odpowiedź, zadziałało dla mnie.
Sam,
Zrobiłem to i mam teraz następujący problem: kiedy dołączam onclick w XML, pojawia się następujący błąd: java.lang.NoSuchMethodException: onClick [klasa android.view.View]
Ramdane Oualitsen
3
Nie zgadzam się z usunięciem vectorDrawables useSupportLibrary = truelinii z gradle. Po usunięciu możesz nadal umieszczać wektory w swoich widokach, ale zmieniają one rozmiar w taki sam sposób, jak pliki png, co oznacza, że ​​zostaną rozciągnięte i staną się ziarniste. Jeśli chcesz, aby urządzenia poniżej 5.0 / API21 faktycznie zmieniały rozmiar wektorów, aby wyglądały ostro, musisz użyć tej linii w pliku gradle. Wstawienie tej linii wywołuje IDE, aby znaleźć obszary, w których nieprawidłowo używasz wektorów, a następnie musisz użyć app:srcCompatprzez XML lub ustawić go za pomocą kodu za pomocąVectorDrawableCompat.create()
Heinous Games
Jak dodać, aby app:drawableEndCompatuzyskać lepszą obsługę RTL? Przyczyna setCompoundDrawablesRelativeWithIntrinsicBoundswymaga co najmniej poziomu API 17.
Dr Jacky,
1
A co z programowym ustawieniem elementu do rysowania?
programista Androida
77

To rozwiązanie nie jest już poprawne. Od wersji 23.3.0 elementy wektorowe można ładować tylko za pośrednictwem aplikacji: srcCompat lub setImageResource ()

Spróbuj zawinąć swój wektor, który można rysować, w listę warstw lub selektor:

<TextView
    android:id="@+id/textView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:drawableRight="@drawable/ic_accessible_white_wrapped"
    android:background="@color/colorPrimary"
    android:textColor="#FFFFFF"
    android:textSize="22sp"
    android:text="Hello World!"/>

ic_accessible_white_wrapped.xml:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/ic_accessible_white_36px"/>
</layer-list>
Alexandr Shutko
źródło
To działa dobrze. Dzięki… Ale wygląda na to, że nie możesz bezpośrednio odwoływać się do pliku SVG w „android: drawableXXXXX”, musisz go opakować w coś innego.
angryITguy
1
Tak. Nie możesz go używać bezpośrednio. Tylko jako aplikacja: srcCompat lub opakowana lub programowo. Zostało to opisane tutaj: android-developers.blogspot.ru/2016/02/…
Alexandr Shutko
Ahh… dzięki… Widzę akapit, do którego się odnosisz. Czy to nadal błąd, jeśli powiedzą ci, żebyś tego nie robił? ;)
angryITguy
1
Myślę, że chodzi o wsteczną kompatybilność. Wygląda na to, że jest jakiś problem z uzyskaniem pełnej obsługi
SVG
2
@HarishGyanani z wersji wsparcia 23.3.0, to już nie jest wsparcie. Musisz dodać więcej poleceń w swoim działaniu: static {if (Build.VERSION.SDK_INT <Build.VERSION_CODES.LOLLIPOP) {AppCompatDelegate.setCompatVectorFromResourcesEnabled (true); }}
Cuong Nguyen,
75

Najlepszy sposób, jaki znalazłem:

Drawable leftDrawable = AppCompatResources.getDrawable(this, R.drawable.ic_search);
search.setCompoundDrawablesWithIntrinsicBounds(leftDrawable, null, null, null);
Hani
źródło
9
Na dzień 25.08.2017 jest to jedyna rzecz, która działa dla mnie (programowe ustawienie rysowania). Właściwie użyłem:Drawable drawable = VectorDrawableCompat.create(getResources(), status.getIconResId(), wrapper.getTheme()); statusButton.setCompoundDrawablesRelativeWithIntrinsicBounds(null, drawable, null, null);
saiyancoder
2
minSdk dla setCompoundDrawablesWithIntrinsicBoundsto 17 . W przeciwnym razie działa to świetnie.
Victor Rendina
1
Jego minSdk to 1, a nie 17, prawdopodobnie wyglądasz na podobny apis. setCompoundDrawablesWithIntrinsicBounds => minSdk 1; setCompoundDrawablesRelativeWithIntrinsicBounds => minSdk 17
正宗 白 布鞋
Najlepsze rozwiązanie do ustawiania programowego, +1
Woton Sampaio,
Użyłem tego z BindingAdapters i działa skutecznie, dzięki!
Ric17101,
61

Aby uzupełnić niektóre odpowiedzi tutaj: możesz sprawić, by VectorDrawable działał jako drawableLeft(itp.), Ale zależy to od wersji Biblioteki Wsparcia i ma swoją cenę.

W jakich przypadkach to działa? Zrobiłem ten diagram jako pomoc (ważny dla Support Library 23.4.0 do - przynajmniej - 25.1.0).

Wektor ściągawka do rysowania

David Ferrand
źródło
2
To świetnie, ale powinieneś poprawić nazwę metody w bloku statycznym nasetCompatVectorFromResourcesEnabled
Vikas Patidar
1
Rozwiązanie setCompatVectorFromResourcesEnabled nie działa na 25.3.1, niestety
Ilja S.
From 23.3.0 version vector drawables can only be loaded via app:srcCompat or setImageResource()więc to rozwiązanie jest przestarzałe i nie będzie działać
użytkownik25
włączenie setCompatVectorFromSourcesEnabled(true)umożliwia ładowanie vectordrawables w android:backgroundsystemie Android 4.x. Więc dziękuję! (Musisz owinąć rzeczywisty wektor w listę warstw pojedynczego elementu)
Peterdk
14

Żadna z pozostałych odpowiedzi nie zadziałała, oto jak dodałem a VectorDrawabledo a TextView, powinieneś użyć, VectorDrawableCompat.create()gdy masz do czynienia z VectorDrawablesponiżej Android L:

TextView titleTextView = (TextView) viewHolder.getView(android.R.id.text1);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
       Drawable leftDrawable = AppCompatResources
                            .getDrawable(context, R.drawable.ic_tickbox);
       titleTextView.setCompoundDrawablesWithIntrinsicBounds(leftDrawable, null, null, null);
}
else
{
      //Safely create our VectorDrawable on pre-L android versions. 
       Drawable leftDrawable = VectorDrawableCompat
                            .create(context.getResources(), R.drawable.ic_tickbox, null);
       titleTextView.setCompoundDrawablesWithIntrinsicBounds(leftDrawable, null, null, null);
}

Krótko, słodko i na temat!

Sakiboy
źródło
To działało dla Androida P i minimalnego poziomu API 26 (docelowy 28)
MiStr
@MiStr - Jest również kompatybilny wstecz :)
Sakiboy
9

Od Google: Począwszy od biblioteki obsługi systemu Android 23.3.0, rysunki wektorowe wsparcia można ładować tylko za pośrednictwem aplikacji: srcCompat lub setImageResource () ..

http://android-developers.blogspot.ru/2016/02/android-support-library-232.html

paulzeng
źródło
1
to oznacza brak rozwiązania na razie
Killer
Spróbuj zawinąć swój wektor do rysowania w listę warstw lub selektor: <TextView android: id = "@ + id / textView" android: layout_width = "match_parent" android: layout_height = "wrap_content" android: drawableRight = "@ drawable / ic_accessible_white_wrapped" android: background = "@ color / colorPrimary" android: textColor = "# FFFFFF" android: textSize = "22sp" android: text = "Hello World!" /> ic_accessible_white_wrapped.xml: <layer-list xmlns: android = " schemas .android.com / apk / res / android "> <item android: drawable =" @ drawable / ic_accessible_white_36px "/> </layer-list>
Wyjątek
9

Możliwe jest bezpośrednie ustawianie rysunków wektorowych w formacie XML, ale musisz uwzględnić strukturę powiązań danych.

Tylko napisz

<TextView
...
android:drawableRight="@{@drawable/ic_accessible_white_36px}"/>

i zawiń cały układ w <layout>tag, więc zasadniczo Twój xml wyglądałby tak:

<?xml version="1.0" encoding="utf-8"?>
<layout>

    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        tools:context="au.com.angryitguy.testsvg.MainActivity">


        <TextView
            android:id="@+id/textView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/colorPrimary"
            android:drawableRight="@{@drawable/ic_accessible_white_36px}"
            android:text="Hello World!"
            android:textColor="#FFFFFF"
            android:textSize="22sp"/>
    </RelativeLayout>
</layout>

Aby aktywować strukturę powiązań danych, po prostu dodaj

android {
    ....
    defaultConfig {
        dataBinding {
            enabled = true
        }
    }
}

Nie musisz używać żadnych innych funkcji biblioteki powiązań

EDYTOWAĆ:

Oczywiście, jeśli chcesz używać rysunków wektorowych przed Lollipopem, musisz włączyć rysunki wektorowe pomocnicze za pomocą

vectorDrawables.useSupportLibrary = true

Więc twoje build.gradlepotrzeby 2 nowych poleceń:

android {
    ....
    defaultConfig {
        vectorDrawables.useSupportLibrary = true
        dataBinding {
            enabled = true
        }
    }
}

dzięki rkmax za uwagę

Hans M
źródło
To dobry pomysł, ale aby to zadziałało, musisz napisać adapter do wiązania. Oto działający przykład: gist.github.com/lisawray/78c33f76809d2bcbbec9983e2c141a70
BladeCoder
1
Muszę powiedzieć, że to działa dla mnie, ale musisz włączyć vectorDrawables.useSupportLibraryna app / build.gradle, a także dodać AppCompatDelegate.setCompatVectorFromResourcesEnabled (true) w aktywności
rkmax
Zapomniałem dodać defaultConfig w tym, build.gradleże może to być powód, dla którego nie działa
Hans M
Dzięki - ratujesz życie!
Van
To niedoceniana odpowiedź!
DYS
6

Przeszedłem przez wszystkie odpowiedzi i korzystając z najnowszego Android Studio 3.0.1 i biblioteki obsługi AppCompat 26.1.0, zapewniam, że to działa dobrze.

W pliku build.gradle (aplikacja)

android {
    compileSdkVersion 26
    defaultConfig {
        vectorDrawables.useSupportLibrary = true
    }
}

dependencies {
    implementation 'com.android.support:appcompat-v7:26.1.0'
}

I w rozszerzaniu działalności AppcompatActivity uwzględnij to zewnętrzne metody, tj. staticBlok

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}  

lub jeśli chcesz, aby zostało to zastosowane do całej aplikacji, po prostu umieść tę linię w rozszerzeniu klasy Application klasę

override fun onCreate() {
    super.onCreate()
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
}

Textview w formacie xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:orientation="vertical">

<TextView
        android:id="@+id/passName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:drawableLeft="@drawable/account_drawableleft_selector"
        android:drawablePadding="5dp"
        android:ellipsize="marquee"
        android:fontFamily="@font/montserrat_light_family"
        android:gravity="center_vertical"
        android:marqueeRepeatLimit="marquee_forever"
        android:paddingRight="10dp"
        android:scrollHorizontally="true"
        android:singleLine="true"
        android:textColor="@color/app_text_color"
        android:textSize="12sp"
        tools:text="Account Name" />
</LinearLayout>

account_drawableleft_selector.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/ic_account_circle_24dp" /> <!-- checked -->
</selector>
Amit Tumkur
źródło
Działa dobrze na jakim interfejsie API? Czy przymierzałeś 19 lub 20?
Divers
Można pokazać, w jaki sposób korzystać drawableRightz TextViewXML?
Divers
2
Podobnie jak w przypadku kilku wymienionych powyżej, jeśli używasz wektora xml bezpośrednio jako drawableLeft, nadal otrzymujesz tę awarię lub wyjątek, więc obejściem jest użycie tego wektorowego xml jako selektora dla drawableLeft dla Textview. Użycie, które możesz zobaczyć w zredagowanej odpowiedzi.
Amit Tumkur,
1
to nie zadziała, nie możesz użyć wektora do rysowania dla TextView bezpośrednio w xml
użytkownik25
Przetestuj w API 19 i 20. Zamiast tego użyłem AppCompatDelegate.setCompatVectorFromResourcesEnabled w klasie aplikacji. Działa jak urok!
Red M
5

Jestem tak późno, aby odpowiedzieć na to pytanie, ponieważ utknąłem późno z tym problemem. Miałem ten sam problem z rysunkami SVG / Vector z TextView. Zamiast tworzyć własne niestandardowe rysunki, jestem w stanie naprawić mój problem za pomocą 2 linii kodu, jak poniżej:

Drawable drawableTop = AppCompatResources.getDrawable(view.getContext(), iconId);
view.setCompoundDrawablesWithIntrinsicBounds(null, drawableTop, null, null);

Mam nadzieję, że to ci pomoże.

Rahul Sharma
źródło
Nie jest kompatybilny z wcześniejszymi Lurządzeniami.
Sakiboy
@Sakiboy Tak, ponieważ używam tego kodu z minimalnym interfejsem API 17.
Rahul Sharma
Nie działa VectorDrawablesna wszystkich urządzeniach z systemem pre-L, po prostu powiedz. Zachowaj ostrożność podczas korzystania z tej odpowiedzi, ponieważ istnieją bezpieczniejsze, dokładniejsze interfejsy API.
Sakiboy
4

Zaprojektowałem do tego małą bibliotekę - bogatą w tekst, z możliwością rysowania (obsługuje również definiowanie rozmiaru i zabarwienia elementów składowych do rysowania).

<com.tolstykh.textviewrichdrawable.TextViewRichDrawable
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Some text"
    app:compoundDrawableHeight="24dp"
    app:compoundDrawableWidth="24dp"
    app:drawableTopVector="@drawable/some_vector_drawble"
    app:drawableEndVector="@drawable/another_vector_drawable"
    app:drawableTint="@color/colorAccent" />

I zależność

compile 'com.tolstykh.textviewrichdrawable:textview-rich-drawable:0.3.2'

wprowadź opis obrazu tutaj

Oleksandr
źródło
3

Jeśli używasz wiązania, istnieje inny magiczny sposób, aby mieć to samo podejście do używania wektorów w TextView. Zawijając je jak:

android:drawableLeft="@{@drawable/vector_ic_access_time_24px}"
android:drawableStart="@{@drawable/vector_ic_access_time_24px}"

To magicznie zadziała, nie badałem, co dzieje się za kulisami, ale myślę, że TextView używa getDrawablemetody z AppCompatResourceslub podobnej.

cesardy
źródło
2

Na podstawie BEHZAD Bahmanyar za odpowiedź , zauważyłem, że nie mogę użyć android normalne atrybuty dla zwykłych plików PNG:

android:drawableTop
android:drawableBottom
etc

ponieważ zostałby zastąpiony przez null in

Drawable drawableTop = null;
...
setCompoundDrawablesRelativeWithIntrinsicBounds(drawableStart, drawableTop, drawableEnd, drawableBottom);

jeśli app:drawableTopCompatnie został ustawiony, ale android:drawableTopzostał (np.).

Oto pełne rozwiązanie:

public class CustomTextView extends AppCompatTextView {
    private static final int NOT_SET = -1;
    private static final int LEFT = 0;
    private static final int START = 0;
    private static final int TOP = 1;
    private static final int RIGHT = 2;
    private static final int END = 2;
    private static final int BOTTOM = 3;

    public CustomTextView(Context context) {
        super(context);
    }

    public CustomTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initAttrs(context, attrs);
    }

    public CustomTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initAttrs(context, attrs);
    }

    void initAttrs(Context context, AttributeSet attrs) {
        if (attrs == null) {
            return;
        }
        Drawable[] drawablesArr = getCompoundDrawables();

        TypedArray attributeArray = context.obtainStyledAttributes(attrs, R.styleable.CustomTextView);
        Drawable drawableStart = null;
        Drawable drawableEnd = null;
        Drawable drawableBottom = null;
        Drawable drawableTop = null;
        Drawable drawableLeft = null;
        Drawable drawableRight = null;

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            drawableStart = attributeArray.getDrawable(R.styleable.CustomTextView_drawableStartCompat);
            drawableEnd = attributeArray.getDrawable(R.styleable.CustomTextView_drawableEndCompat);
            drawableBottom = attributeArray.getDrawable(R.styleable.CustomTextView_drawableBottomCompat);
            drawableTop = attributeArray.getDrawable(R.styleable.CustomTextView_drawableTopCompat);
            drawableLeft = attributeArray.getDrawable(R.styleable.CustomTextView_drawableLeftCompat);
            drawableRight = attributeArray.getDrawable(R.styleable.CustomTextView_drawableRightCompat);
        } else {
            final int drawableStartId = attributeArray.getResourceId(R.styleable.CustomTextView_drawableStartCompat, NOT_SET);
            final int drawableEndId = attributeArray.getResourceId(R.styleable.CustomTextView_drawableEndCompat, NOT_SET);
            final int drawableBottomId = attributeArray.getResourceId(R.styleable.CustomTextView_drawableBottomCompat, NOT_SET);
            final int drawableTopId = attributeArray.getResourceId(R.styleable.CustomTextView_drawableTopCompat, NOT_SET);
            final int drawableLeftId = attributeArray.getResourceId(R.styleable.CustomTextView_drawableLeftCompat, NOT_SET);
            final int drawableRightId = attributeArray.getResourceId(R.styleable.CustomTextView_drawableRightCompat, NOT_SET);

            if (drawableStartId != NOT_SET)
                drawableStart = AppCompatResources.getDrawable(context, drawableStartId);
            if (drawableLeftId != NOT_SET)
                drawableLeft = AppCompatResources.getDrawable(context, drawableLeftId);
            if (drawableEndId != NOT_SET)
                drawableEnd = AppCompatResources.getDrawable(context, drawableEndId);
            if (drawableRightId != NOT_SET)
                drawableRight = AppCompatResources.getDrawable(context, drawableRightId);
            if (drawableBottomId != NOT_SET)
                drawableBottom = AppCompatResources.getDrawable(context, drawableBottomId);
            if (drawableTopId != NOT_SET)
                drawableTop = AppCompatResources.getDrawable(context, drawableTopId);
        }

        drawableStart = (drawableStart != null ? drawableStart : drawablesArr[START]);
        drawableLeft = (drawableLeft != null ? drawableLeft : drawablesArr[LEFT]);
        drawableStart = (drawableStart != null ? drawableStart : drawableLeft);

        drawableEnd = (drawableEnd != null ? drawableEnd : drawablesArr[END]);
        drawableRight = (drawableRight != null ? drawableRight : drawablesArr[RIGHT]);
        drawableEnd = (drawableEnd != null ? drawableEnd : drawableRight);

        drawableBottom = (drawableBottom != null ? drawableBottom : drawablesArr[BOTTOM]);
        drawableTop = (drawableTop != null ? drawableTop : drawablesArr[TOP]);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            setCompoundDrawablesRelativeWithIntrinsicBounds(drawableStart, drawableTop, drawableEnd, drawableBottom);
        } else {
            setCompoundDrawables(drawableStart, drawableTop, drawableEnd, drawableBottom);
        }

        attributeArray.recycle();
    }
}
Goran Horia Mihail
źródło
To powinna zostać zaakceptowana odpowiedź. pracuj z normalnymi plikami png i atrybutami drawableTop, drawableBottom. Zaakceptowana odpowiedź nie działa z plikiem png i atrybutami drawableTop, drawableBottom.
Bhargav Pandya
2

W pliku build.gradle (aplikacja)

android {
    compileSdkVersion 26
    defaultConfig {
        vectorDrawables.useSupportLibrary = true
    }

    dataBinding {
        enabled = true
    }
}

...

public class BindingUtils {
    @BindingAdapter("android:drawableRight")
    public static void setDrawableStart(TextView textView, int resourceId) {
        Drawable drawable = AppCompatResources.getDrawable(textView.getContext(), resourceId);
        Drawable[] drawables = textView.getCompoundDrawables();
        textView.setCompoundDrawablesWithIntrinsicBounds(drawable,
                drawables[1], drawables[2], drawables[3]);
    } 
}

użyj (podczas wiązania danych)

android:drawableRight="@{viewModel.ResId}"

Lub (normalny)

android:drawableRight="@{@drawable/ic_login_24dp}"
Ahmad Aghazadeh
źródło
1

Za pomocą Vector Drawables użyj

kotlin

 val drawable1 = VectorDrawableCompat.create(resources, R.drawable.ic_rb_username, theme)
        yourView.setCompoundDrawablesRelativeWithIntrinsicBounds( drawable1, null, null, null)

Jawa

  Drawable drawable1 = VectorDrawableCompat.create(getResources(), R.drawable.ic_rb_username, getTheme());
        yourView.setCompoundDrawablesRelativeWithIntrinsicBounds( drawable1, null, null, null);
Margines
źródło
1

Aby zapewnić zgodność z poprzednimi wersjami, użyj:

TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(textView, left, top, right, bottom)
Shayan_Aryan
źródło
0

Używam Binding adaptera do rozwiązania tego problemu

@JvmStatic
@BindingAdapter("drawableSvgLeft")
fun addDrawableSvgLeft(textView: TextView,drawable: Drawable){
    textView.setCompoundDrawablesWithIntrinsicBounds(drawable,null,null,null)
}

@JvmStatic
@BindingAdapter("drawableSvgRight")
fun addDrawableSvgRight(textView: TextView,drawable: Drawable){
    textView.setCompoundDrawablesWithIntrinsicBounds(null,null,drawable,null)
}

a także używając w ten sposób w moim układzie

<TextView
  drawableSvgRight="@{@drawable/svg_ic_battle_trophy}"
  .....

prawdopodobnie vectorDrawables.useSupportLibrary = true w domyślnej konfiguracji jest konieczne

mahdi ZTD
źródło