【问题标题】:Is it possible to use VectorDrawable in Buttons and TextViews using android:DrawableRight?是否可以使用 android:DrawableRight 在 Buttons 和 TextViews 中使用 VectorDrawable?
【发布时间】:2016-06-16 03:45:51
【问题描述】:

当我在 textview 或 imageview 中使用 VectorDrawable 资源时,在使用“android:DrawableRight”/“android:DrawableEnd”/“android:DrawableStart”/“android:DrawableLeft”时会出现运行时崩溃。

应用程序可以正常编译,不会出现任何警告。

我正在使用

  • Gradle 1.5
  • 支持库 23.2 ('com.android.support:appcompat-v7:23.2.0')

但我发现,我可以在 Java 中以编程方式分配 SVG,而不会发生这样的崩溃。

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

(我怀疑这是 23.2 的支持库错误。)

但是是否可以将 drawableRight 等用于 SVG 资产?

这是我的布局

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

这是我的活动

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

        }
    }

这是来自 Google 材料设计网站的未经修改的 VectorDrawable 资源。

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

这是我的应用 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'
}

这是崩溃。 (注意引用 textview 的 inflate 错误。)

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

【问题讨论】:

  • 不,你不能,因为 SVG 文件本身不支持。您必须改用 VectorDrawable(它只使用 SVG 规范的一个子集)。
  • 要了解如何将 VectorDrawable 与 drawableLeft、drawableRight、drawableTop、drawableBottom 一起使用,请查看This answer
  • 我发现这对我有用:android.jlelse.eu/…

标签: java android android-layout android-vectordrawable compound-drawables


【解决方案1】:

是否可以对 SVG 资产使用 drawableRight 等?

是的

AppCompatTextView now 支持 app:drawableLeftCompatapp:drawableTopCompatapp:drawableRightCompatapp:drawableBottomCompatapp:drawableStartCompatapp:drawableEndCompat 复合可绘制对象,支持向后移植的可绘制类型,例如 VectorDrawableCompat .

将其包含在您的 gradle 文件中

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

您可以在文本视图中使用

app:drawableLeftCompat
app:drawableStartCompat

如果您在按钮中使用 app:drawableLeftCompat、app:drawableStartCompat 时遇到问题,您需要将库更新为

androidx.appcompat:appcompat:1.2.0-alpha01

他们有一个错误

androidx.appcompat:appcompat:1.1.0-alpha01

你可以看到docs


或者如果您还不想更新,那么:

因为 Google 似乎不会在短期内对这个问题采取任何措施,所以我不得不为我的所有应用想出一个更可靠的可重用解决方案:

  1. 首先在应用的 attrs.xml 文件中添加自定义 TextView 属性“res/values/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. 然后像这样创建自定义 TextView 类:

    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. 现在您可以通过自定义属性在任何布局中轻松使用它:

    <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 -->
        />
    
    • 您可以使用 ButtonEditTextRadioButton 做类似的事情,因为它们派生自 TextView

希望这会有所帮助:)

【讨论】:

  • 非常有用的答案。无论如何,我也推荐阅读Dadou's very complete answer。从我的build.gradle 中删除vectorDrawables { useSupportLibrary = true },因为该答案表明对我有用。
  • 我这样做了,现在我遇到了以下问题:当我在 XML 中附加 onclick 时,出现以下错误:java.lang.NoSuchMethodException: onClick [class android.view.View]
  • 我不同意从 gradle 中删除 vectorDrawables useSupportLibrary = true 行。当你删除它时,你仍然可以将矢量放在你的视图中,但它们的大小调整方式与 png 相同,这意味着它们将被拉伸并变得颗粒状。如果您希望低于 5.0/API21 的设备实际正确调整矢量大小以使它们看起来清晰,则必须在 gradle 文件中使用该行。将该行放入调用 IDE 以查找您错误地使用向量的区域,然后您必须通过 XML 使用 app:srcCompat 或通过带有 VectorDrawableCompat.create() 的代码设置它
  • 如何添加 app:drawableEndCompat 以获得更好的 RTL 支持?因为setCompoundDrawablesRelativeWithIntrinsicBounds 至少需要 API 级别 17。
  • 以编程方式设置drawable怎么样?
【解决方案2】:

我发现的最好方法:

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

【讨论】:

  • 截至 2017 年 8 月 25 日,这是唯一对我有用的东西(以编程方式设置可绘制对象)。我实际使用过:Drawable drawable = VectorDrawableCompat.create(getResources(), status.getIconResId(), wrapper.getTheme()); statusButton.setCompoundDrawablesRelativeWithIntrinsicBounds(null, drawable, null, null);
  • setCompoundDrawablesWithIntrinsicBounds 的 minSdk 为 17。否则效果很好。
  • 它的 minSdk 是 1 而不是 17,你可能看起来类似的 api。 setCompoundDrawablesWithIntrinsicBounds => minSdk 1; setCompoundDrawablesRelativeWithIntrinsicBounds => minSdk 17
  • 编程设置的最佳解决方案,+1
  • 我将它与 BindingAdapters 一起使用,效果很好,谢谢!
【解决方案3】:

此解决方案不再正确。从 23.3.0 版本开始,矢量可绘制对象只能通过 app:srcCompat 或 setImageResource()

加载

尝试将矢量可绘制对象包装到图层列表或选择器中:

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

【讨论】:

  • 这很好用。谢谢.. 但是您似乎不能直接在“android:drawableXXXXX”中引用 SVG,您必须将其包装在其他东西中。
  • 是的。你不能直接使用它。仅作为 app:srcCompat 或包装或以编程方式。此处对此进行了描述:android-developers.blogspot.ru/2016/02/…
  • 啊..谢谢..我可以看到你所指的段落。那么,如果他们告诉你不要这样做,这仍然是一个错误吗? ;)
  • 我认为这完全是为了向后兼容。似乎获得完整的 svg 支持有些问题,所以他们做了一些变通方法......
  • @HarishGyanani 来自支持版本 23.3.0,不再支持。您必须在活动中添加更多命令: static { if (Build.VERSION.SDK_INT
【解决方案4】:

为了补充这里的一些答案:您可以让 VectorDrawable 以 drawableLeft 的身份工作(等等),但这取决于支持库版本,并且需要付出代价。

在哪些情况下有效?我已经让this diagram 提供帮助(对支持库 23.4.0 到 - 至少 - 25.1.0 有效)。

【讨论】:

  • 这很好,但您应该将静态块中的方法名称更正为 setCompatVectorFromResourcesEnabled
  • setCompatVectorFromResourcesEnabled 解决方案在 25.3.1 上不起作用,很遗憾
  • From 23.3.0 version vector drawables can only be loaded via app:srcCompat or setImageResource() 所以这个解决方案已被弃用并且不起作用
  • 启用setCompatVectorFromSourcesEnabled(true) 可以在Android 4.x 上的android:background 中加载vectordrawables。那谢谢啦! (您确实需要将实际矢量包装在单个项目层列表中)
【解决方案5】:

其他答案均无效,这是我将VectorDrawable 添加到TextView 的方法,在处理VectorDrawables 下面的VectorDrawables 时应使用VectorDrawableCompat.create()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);
}

简短、甜美、切中要害!

【讨论】:

  • 这适用于 Android P,最低 API 级别 26(目标 28)
  • @MiStr - 它也向后兼容 :)
【解决方案6】:

来自 Google:从 Android 支持库 23.3.0 开始,支持向量 drawables 只能通过 app:srcCompat 或 setImageResource() 加载..

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

【讨论】:

  • 这意味着暂时没有解决方案
  • 尝试将您的矢量可绘制对象包装到图层列表或选择器中: ic_accessible_white_wrapped.xml: schemas.android.com/apk/res/android">
【解决方案7】:

可以直接在xml中设置矢量drawables,但是你已经包含了数据绑定框架。

随便写

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

并将整个布局包装在 &lt;layout&gt; 标记中,所以基本上你的 xml 看起来像:

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

要激活数据绑定框架,只需添加

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

您不必使用绑定库的任何其他功能

编辑:

当然,如果您想在 Lollipop 之前使用矢量可绘制对象,则必须启用支持矢量可绘制对象

vectorDrawables.useSupportLibrary = true

所以你的 build.gradle 需要 2 个新命令:

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

感谢rkmax的评论

【讨论】:

  • 这是个好主意,但是您需要编写一个绑定适配器才能使其工作。这是一个工作示例:gist.github.com/lisawray/78c33f76809d2bcbbec9983e2c141a70
  • 我必须说这对我有用,但您必须在 app/build.gradle 上启用 vectorDrawables.useSupportLibrary 并在活动上添加 AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
  • 我忘记在 build.gradle 中添加 defaultConfig 这可能是它不起作用的原因
  • 谢谢 - 你是一个救生员!
  • 这是一个被低估的答案!
【解决方案8】:

我浏览了所有答案并使用了最新的 Android Studio 3.0.1 和 AppCompat Support Library 26.1.0,我可以保证这一切正常。

build.gradle (app) 文件中

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

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

并在扩展AppcompatActivity 的活动中将其包含在外部 方法,即 static

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}  

或者如果您希望将其应用于整个应用程序,只需在其中包含此行 扩展Application类的类

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

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>

【讨论】:

  • 在什么 API 上运行良好?你是在 19 号还是 20 号试的?
  • 您能说明如何在 XML 中使用 drawableRight 代替 TextView 吗?
  • 就像上面提到的一样,如果你直接使用矢量 xml 作为 drawableLeft,你仍然会遇到这个崩溃或异常,因此解决方法是使用该矢量 xml 作为 Textview 的 drawableLeft 的选择器。您可以在编辑后的答案中看到用法。
  • 不行,不能直接在xml中为TextView使用vector drawable
  • 在 API 19 和 20 中测试它。我在应用程序类中使用了 AppCompatDelegate.setCompatVectorFromResourcesEnabled。像魅力一样工作!
【解决方案9】:

截至androidx.appcompat:appcompat:1.1.0,您可以使用

app:drawableLeftCompat
app:drawableStartCompat
...

【讨论】:

  • 似乎这个属性不适用于数据绑定?
【解决方案10】:

我回答这个问题太晚了,因为我迟迟没有解决这个问题。我对带有 TextView 的 svg/vector drawables 有同样的问题。我可以使用以下两行代码来解决我的问题,而不是制作您自己的自定义可绘制对象:

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

希望对你有所帮助。

【讨论】:

  • 与之前的L 设备不兼容。
  • @Sakiboy 是的,因为我正在使用此代码和最低 api 17。
  • 不适用于 VectorDrawables 在所有运行 pre-L 的设备上,只是说。使用此答案时要小心,因为有更安全、更准确的 API 可供使用。
【解决方案11】:

我为此设计了一个小型库 - textview-rich-drawable(它还支持定义复合绘图的大小和着色)。

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

以及依赖

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

【讨论】:

    【解决方案12】:

    如果您使用绑定,还有另一种神奇的方法可以在 TextView 中使用相同的方法。像这样包装它们:

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

    这会神奇地起作用,我还没有调查幕后发生的事情,但我猜 TextView 正在使用 AppCompatResources 或类似方法中的 getDrawable 方法。

    【讨论】:

      【解决方案13】:

      基于 Behzad Bahmanyar 的 answer,我注意到我无法将 android 的正常属性用于普通 png 文件:

      android:drawableTop
      android:drawableBottom
      etc
      

      因为它会被替换为 null in

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

      如果app:drawableTopCompat 未设置,但android:drawableTop 已设置(例如)。

      这里是完整的解决方案:

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

      【讨论】:

      • 这应该是被接受的答案。使用普通的 png 文件和属性 drawableTop, drawableBottom 。接受的答案不适用于 png 文件和 drawableTop,drawableBottom 属性。
      【解决方案14】:

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

      使用(当数据绑定时)

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

      或(普通)

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

      【讨论】:

        【解决方案15】:

        使用 Vector Drawable 使用

        科特林

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

        【讨论】:

          【解决方案16】:

          为了向后兼容使用:

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

          【讨论】:

            【解决方案17】:

            我正在使用绑定适配器来解决这个问题

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

            并且在我的布局中也以这种方式使用

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

            可能是vectorDrawables.useSupportLibrary = true 在默认配置中是必要的

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-07-04
              • 1970-01-01
              • 2017-09-24
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多