Ist es möglich, VectorDrawable in Buttons und TextViews mit android: DrawableRight zu verwenden?


120

Wenn ich VectorDrawable-Assets in einer Text- oder Bildansicht verwende, tritt bei Verwendung von "android: DrawableRight" / "android: DrawableEnd" / "android: DrawableStart" / "android: DrawableLeft" ein Laufzeitabsturz auf.

Die App wird ohne Warnungen problemlos kompiliert.

ich benutze

  • Gradle 1.5
  • Support Library 23.2 ('com.android.support:appcompat-v7:23.2.0')

Was ich jedoch festgestellt habe, ist, dass ich SVGs in Java programmgesteuert zuweisen kann, ohne dass es zu solchen Abstürzen kommt.

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

(Ich vermute, dies ist ein Fehler in der Support-Bibliothek für 23.2.)

Aber ist es möglich, drawableRight usw. für SVG-Assets zu verwenden?

Hier ist mein Layout

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

Hier ist meine Aktivität

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

        }
    }

Hier ist das unveränderte VectorDrawable-Asset von Googles Materialdesign-Website.

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

Hier ist meine App 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'
}

Hier ist der Absturz. (Beachten Sie die Aufblasfehler, die auf die Textansicht verweisen.)

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

Nein, das können Sie nicht, da SVG-Dateien nicht nativ unterstützt werden . Sie müssen stattdessen ein VectorDrawable verwenden (das nur eine Teilmenge der SVG-Spezifikationen verwendet).
Phantômaxx

2
Um zu sehen, wie VectorDrawable mit drawableLeft, drawableRight, drawableTop, drawableBottom verwendet wird, lesen Sie diese Antwort
Behzad Bahmanyar

Ich fand das funktioniert für mich: android.jlelse.eu/…
Huy Tower

Antworten:


185

Ist es möglich, drawableRight usw. für SVG-Assets zu verwenden?

Ja

AppCompatTextView jetzt Stützen app:drawableLeftCompat, app:drawableTopCompat, app:drawableRightCompat, app:drawableBottomCompat, app:drawableStartCompatund app:drawableEndCompatVerbindung Drawables, drawable Typen zurück portiert Stütz wie VectorDrawableCompat.

Fügen Sie dies in Ihre Gradle-Datei ein

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

In Ihrer Textansicht können Sie verwenden

app:drawableLeftCompat
app:drawableStartCompat

Wenn Sie Probleme bei der Verwendung von app: drawableLeftCompat, app: drawableStartCompat in Schaltflächen haben, müssen Sie Ihre Bibliothek auf aktualisieren

androidx.appcompat: appcompat: 1.2.0-alpha01

Sie hatten einen Fehler

androidx.appcompat: appcompat: 1.1.0-alpha01

Sie können die Dokumente sehen


Oder wenn Sie noch nicht aktualisieren möchten, dann:

Da Google anscheinend in naher Zukunft nichts gegen dieses Problem unternehmen wird, musste ich für alle meine Apps eine solide wiederverwendbare Lösung finden:

  1. Fügen Sie zuerst benutzerdefinierte TextView- Attribute in die Datei attrs.xml Ihrer App "res / values ​​/ attrs.xml" ein :

    <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. Erstellen Sie dann eine benutzerdefinierte TextView-Klasse wie folgt:

    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. Jetzt können Sie es einfach in beliebigen Layouts mit Ihren benutzerdefinierten Attributen verwenden:

    <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 -->
        />
    • Ähnliches können Sie mit Button , EditText und RadioButton tun, da diese von TextView abgeleitet sind

Hoffe das hilft :)


4
Sehr nützliche Antwort. Wie auch immer, ich empfehle auch Dadous sehr vollständige Antwort zu lesen . Das Entfernen vectorDrawables { useSupportLibrary = true }von meiner, build.gradlewie diese Antwort nahelegt, hat für mich funktioniert.
Sam

Ich habe das getan und habe jetzt das folgende Problem: Wenn ich den Onclick in XML anhänge, erhalte ich die folgende Fehlermeldung: java.lang.NoSuchMethodException: onClick [Klasse android.view.View]
Ramdane Oualitsen

3
Ich bin nicht einverstanden mit der Entfernung der vectorDrawables useSupportLibrary = trueLinie aus dem Gradle. Wenn Sie es entfernen, können Sie weiterhin Vektoren in Ihre Ansichten einfügen, deren Größe jedoch auf die gleiche Weise wie pngs geändert wird. Dies bedeutet, dass sie gedehnt werden und körnig werden. Wenn Geräte unter 5.0 / API21 die Größe der Vektoren tatsächlich korrekt ändern sollen, damit sie klar aussehen, müssen Sie diese Zeile in der Gradle-Datei verwenden. Wenn Sie diese Zeile eingeben, wird die IDE aufgerufen, um Bereiche zu finden, in denen Sie Vektoren falsch verwenden. Anschließend müssen Sie das app:srcCompatVia-XML verwenden oder es per Code mitVectorDrawableCompat.create()
Heinous Games

Wie füge ich app:drawableEndCompatfür eine bessere RTL-Unterstützung hinzu? Ursache setCompoundDrawablesRelativeWithIntrinsicBoundsbenötigt mindestens API-Level 17.
Dr.jacky

1
Was ist mit dem programmgesteuerten Einstellen des Zeichens?
Android-Entwickler

77

Diese Lösung ist nicht mehr korrekt. Ab der Version 23.3.0 können Vektor-Drawables nur über die App geladen werden: srcCompat oder setImageResource ()

Versuchen Sie, Ihren Vektor in eine Ebenenliste oder einen Selektor zu packen:

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

Das funktioniert gut. Danke. Aber es scheint, dass Sie in "android: drawableXXXXX" nicht direkt auf eine SVG verweisen können. Sie müssen sie in etwas anderes einwickeln.
wütendITguy

1
Ja. Sie können es nicht direkt verwenden. Nur als App: srcCompat oder verpackt oder programmgesteuert. Dies wurde hier beschrieben: android-developers.blogspot.ru/2016/02/…
Alexandr Shutko

Ahh .. danke .. Ich kann den Absatz sehen, auf den Sie sich beziehen. Also, ist es immer noch ein Fehler, wenn sie dir sagen, dass du es nicht tun sollst? ;)
wütendITguy

1
Ich denke, es geht nur um Abwärtskompatibilität. Es sieht so aus, als ob es ein Problem gibt, volle SVG-Unterstützung zu erhalten, also haben sie einige
Problemumgehungen

2
@ HarishGyanani ab Support-Version 23.3.0, es ist keine längere Unterstützung. Sie müssen Ihrer Aktivität weitere Befehle hinzufügen: static {if (Build.VERSION.SDK_INT <Build.VERSION_CODES.LOLLIPOP) {AppCompatDelegate.setCompatVectorFromResourcesEnabled (true); }}
Cuong Nguyen

75

Der beste Weg, den ich gefunden habe:

Drawable leftDrawable = AppCompatResources.getDrawable(this, R.drawable.ic_search);
search.setCompoundDrawablesWithIntrinsicBounds(leftDrawable, null, null, null);

9
Ab dem 25.08.17 ist dies das einzige, was für mich funktioniert (programmierbares Einstellen des Zeichens). Ich habe tatsächlich verwendet:Drawable drawable = VectorDrawableCompat.create(getResources(), status.getIconResId(), wrapper.getTheme()); statusButton.setCompoundDrawablesRelativeWithIntrinsicBounds(null, drawable, null, null);
Saiyancoder

2
minSdk für setCompoundDrawablesWithIntrinsicBoundsist 17 . Ansonsten funktioniert das super.
Victor Rendina

1
Sein minSdk ist 1 nicht 17, Sie sehen wahrscheinlich die ähnliche apis. setCompoundDrawablesWithIntrinsicBounds => minSdk 1; setCompoundDrawablesRelativeWithIntrinsicBounds => minSdk 17
布鞋 白 布鞋

Beste Lösung für die programmgesteuerte Einstellung, +1
Woton Sampaio

Ich habe dies mit BindingAdapters verwendet und funktioniert effektiv, danke!
Ric17101

61

Um einige der Antworten hier zu ergänzen: Sie können VectorDrawable als drawableLeft(usw.) verwenden, dies hängt jedoch von der Version der Support-Bibliothek ab und ist mit einem Preis verbunden.

In welchen Fällen funktioniert es? Ich habe dieses Diagramm erstellt , um zu helfen (gültig für Support Library 23.4.0 bis - mindestens - 25.1.0).

VectorDrawable Cheatsheet


2
Es ist großartig, aber Sie sollten den Methodennamen im statischen Block aufsetCompatVectorFromResourcesEnabled
Vikas Patidar

1
setCompatVectorFromResourcesEnabled-Lösung funktioniert leider nicht auf 25.3.1
Ilja S.

From 23.3.0 version vector drawables can only be loaded via app:srcCompat or setImageResource()
Daher

Durch Aktivieren setCompatVectorFromSourcesEnabled(true)können vectordrawables android:backgroundunter Android 4.x geladen werden. So danke! (Sie müssen den tatsächlichen Vektor in eine einzelne Element-Layer-Liste
einschließen

14

Keine der anderen Antworten hat funktioniert. Hier ist, wie ich ein VectorDrawablezu einem hinzugefügt habe TextView, das Sie verwenden sollten, VectorDrawableCompat.create()wenn Sie sich mit VectorDrawablesunten befassen 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);
}

Kurz, süß und auf den Punkt!


Dies funktionierte für Android P und min API Level 26 (Ziel 28)
MiStr

@ MiStr - Es ist auch abwärtskompatibel :)
Sakiboy

9

Von Google: Ab Android Support Library 23.3.0 können Support-Vektor-Drawables nur über die App geladen werden: srcCompat oder setImageResource ().

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


1
das bedeutet
Killer

Versuchen Sie, Ihren Vektor in eine Ebenenliste oder einen Selektor zu packen: <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 = "Hallo Welt!" /> ic_accessible_white_wrapped.xml: <Ebenenliste xmlns: android = " Schemas .android.com / apk / res / android "> <item android: drawable =" @ drawable / ic_accessible_white_36px "/> </ layer-list>
Null-Zeiger-Ausnahme

9

Es ist möglich, Vektor-Drawables direkt in XML festzulegen, Sie haben jedoch das Datenbindungs-Framework hinzugefügt.

Einfach schreiben

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

und wickeln Sie Ihr gesamtes Layout in ein <layout>Tag ein, sodass Ihre XML im Grunde so aussehen würde:

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

Um das Datenbindungs-Framework zu aktivieren, fügen Sie einfach hinzu

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

Sie müssen keine anderen Funktionen der Bindungsbibliothek verwenden

BEARBEITEN:

Wenn Sie Vektor-Drawables vor Lollipop verwenden möchten, müssen Sie natürlich die Unterstützung von Vektor-Drawables mit aktivieren

vectorDrawables.useSupportLibrary = true

Sie build.gradlebenötigen also 2 neue Befehle:

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

danke an rkmax für die bemerkung


Dies ist eine gute Idee, aber Sie müssen einen Bindungsadapter schreiben, damit dies funktioniert. Hier ist ein funktionierendes Beispiel: gist.github.com/lisawray/78c33f76809d2bcbbec9983e2c141a70
BladeCoder

1
Ich muss sagen, dass dies für mich funktioniert, aber Sie müssen es vectorDrawables.useSupportLibraryauf app / build.gradle aktivieren und AppCompatDelegate.setCompatVectorFromResourcesEnabled (true) für die Aktivität
hinzufügen

Ich habe vergessen, defaultConfig hinzuzufügen build.gradle, das könnte der Grund sein, warum es nicht funktioniert
Hans M

Danke - du bist ein Lebensretter!
Van

Dies ist eine unterschätzte Antwort!
DYS

6

Ich habe alle Antworten durchgesehen und mit dem neuesten Android Studio 3.0.1 und der AppCompat Support Library 26.1.0 sichergestellt, dass dies einwandfrei funktioniert.

In der Datei build.gradle (App)

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

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

Und in der Aktivitätserweiterung AppcompatActivitysind diese externen Methoden enthalten, dh ein staticBlock

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}  

oder wenn Sie wollen , dass diese nur auf ganze app angewendet werden , umfassen diese Zeile innerhalb der Klasse erstreckt ApplicationKlasse

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

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

Funktioniert gut auf welcher API? Hast du 19 oder 20 anprobiert?
Taucher

Können Sie zeigen , wie Sie verwenden drawableRightfür TextViewin XML?
Taucher

2
Wie oben erwähnt, erhalten Sie, wenn Sie Vektor-XML direkt als drawableLeft verwenden, immer noch diesen Absturz oder diese Ausnahme. Daher besteht die Problemumgehung darin, diesen Vektor-XML als Selektor für drawableLeft für Textview zu verwenden. Verwendung u kann in bearbeiteter Antwort sehen.
Amit Tumkur

1
Es wird nicht funktionieren. Sie können den für TextView zeichnbaren Vektor nicht direkt in XML verwenden.
user25

Testen Sie es in API 19 und 20. Ich habe stattdessen AppCompatDelegate.setCompatVectorFromResourcesEnabled in der Anwendungsklasse verwendet. Arbeiten wie ein Zauber!
Red M


5

Ich bin so spät dran, diese Frage zu beantworten, da ich mich zu spät mit diesem Problem befasst habe. Ich hatte das gleiche Problem mit svg / vector drawables mit TextView. Anstatt Ihre eigenen Zeichen zu erstellen, kann ich mein Problem mit zwei Codezeilen wie folgt beheben:

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

Hoffe es wird dir helfen.


Nicht kompatibel mit Pre- LGeräten.
Sakiboy

@ Sakiboy Ja, das ist es, da ich diesen Code mit mindestens API 17 verwende.
Rahul Sharma

Funktioniert nicht mit VectorDrawablesallen Geräten, auf denen Pre-L ausgeführt wird. Seien Sie vorsichtig, wenn Sie diese Antwort verwenden, da sicherere und genauere APIs verwendet werden können.
Sakiboy

4

Ich habe dafür eine winzige Bibliothek entworfen - textview-rich-drawable (sie unterstützt auch das Definieren der Größe und des Farbtons der zusammengesetzten Drawables).

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

Und die Abhängigkeit

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

Geben Sie hier die Bildbeschreibung ein


3

Wenn Sie die Bindung verwenden, gibt es eine andere magische Möglichkeit, Vektoren in einer Textansicht auf dieselbe Weise zu verwenden. Wickeln Sie sie wie folgt ein:

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

Das wird auf magische Weise funktionieren. Ich habe nicht untersucht, was hinter den Kulissen passiert, aber ich denke, dass TextView die getDrawableMethode von AppCompatResourcesoder ähnlich verwendet.


2

Aufgrund der Antwort von Behzad Bahmanyar bemerkte ich, dass ich die normalen Attribute von Android nicht für normale PNG-Dateien verwenden konnte:

android:drawableTop
android:drawableBottom
etc

weil es durch null in ersetzt würde

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

wenn das app:drawableTopCompatnicht gesetzt war, aber android:drawableTopwar (zum Beispiel).

Hier ist die vollständige Lösung:

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

Dies sollte als Antwort akzeptiert werden. Arbeiten Sie mit normalen PNG-Dateien und -Attributen. drawableTop, drawableBottom. Die akzeptierte Antwort funktioniert nicht mit den Attributen png-Datei und drawableTop, drawableBottom.
Bhargav Pandya

2

In der Datei build.gradle (App)

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

Verwenden Sie (beim Datenbinden)

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

Oder (normal)

android:drawableRight="@{@drawable/ic_login_24dp}"

1

Verwenden von Vector Drawables verwenden

Kotlin

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

Java

  Drawable drawable1 = VectorDrawableCompat.create(getResources(), R.drawable.ic_rb_username, getTheme());
        yourView.setCompoundDrawablesRelativeWithIntrinsicBounds( drawable1, null, null, null);

1

Verwenden Sie zur Abwärtskompatibilität Folgendes:

TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(textView, left, top, right, bottom)

0

Ich benutze den Bindungsadapter, um dieses Problem zu lösen

@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)
}

und auch auf diese Weise in meinem Layout verwenden

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

wahrscheinlich ist vectorDrawables.useSupportLibrary = true in der Standardkonfiguration erforderlich

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.