是否可以使用android:DrawableRight在Buttons和TextViews中使用VectorDrawable?

ang*_*guy 117 java android android-layout compound-drawables android-vectordrawable

当我在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);
Run Code Online (Sandbox Code Playgroud)

(我怀疑这是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>
Run Code Online (Sandbox Code Playgroud)

这是我的活动

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

        }
    }
Run Code Online (Sandbox Code Playgroud)

以下是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>
Run Code Online (Sandbox Code Playgroud)

这是我的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'
}
Run Code Online (Sandbox Code Playgroud)

这是崩溃.(注意引用textview的膨胀错误.)

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) 
...
Run Code Online (Sandbox Code Playgroud)

Beh*_*yar 169

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

AppCompatTextView 现在支持app:drawableLeftCompat,app:drawableTopCompat,app:drawableRightCompat,app:drawableBottomCompat,app:drawableStartCompatapp:drawableEndCompat化合物可绘,支持向后移植可拉伸类型,例如VectorDrawableCompat.

将其包含在您的gradle文件中

implementation 'androidx.appcompat:appcompat:1.1.0-alpha01'
Run Code Online (Sandbox Code Playgroud)

在文本视图中,您可以使用

app:drawableLeftCompat
app:drawableStartCompat
Run Code Online (Sandbox Code Playgroud)

老答案

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

  1. 首先在应用程序"res/values/attrs.xml"的 attrs.xml文件中添加自定义TextView属性:

    <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>
    
    Run Code Online (Sandbox Code Playgroud)
  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();
            }
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  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 -->
        />
    
    Run Code Online (Sandbox Code Playgroud)
    • 您可以使用Button,EditTextRadioButton执行类似的操作,因为它们是从TextView派生的

希望这可以帮助 :)

  • 非常有用的答案.无论如何,我建议也阅读[Dadou非常完整的答案](/sf/answers/2929919401/).从我的`build.gradle`中删除`vectorDrawables {useSupportLibrary = true}`,因为答案显示对我有用. (4认同)
  • 我不同意从gradle中删除`vectorDrawables useSupportLibrary = true`行.当你删除它时,你仍然可以将矢量放在你的视图中,但它们的调整大小与pngs相同,这意味着它们会被拉伸并变得颗粒状.如果您希望低于5.0/API21的设备实际正确调整向量的大小,使它们看起来很清晰,则必须在gradle文件中使用该行.将该行放入IDE中以查找错误地使用向量的区域,然后必须通过XML使用`app:srcCompat`或通过带有`VectorDrawableCompat.create()的代码设置它. (3认同)

Ale*_*tko 77

此解决方案不再正确.从23.3.0版本开始,矢量drawable只能通过app:srcCompat或setImageResource()加载

尝试将矢量drawable包装到layer-list或selector中:

<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!"/>
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

  • @HarishGyanani来自支持版本23.3.0,它没有长期支持.您必须在活动中添加更多命令:static {if(Build.VERSION.SDK_INT <Build.VERSION_CODES.LOLLIPOP){AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); }} (2认同)

Han*_*ani 68

我找到的最佳方式:

Drawable leftDrawable = AppCompatResources.getDrawable(this, R.drawable.ic_search);
search.setCompoundDrawablesWithIntrinsicBounds(leftDrawable, null, null, null);
Run Code Online (Sandbox Code Playgroud)

  • 从8/25/17开始,这是唯一对我有用的东西(以编程方式设置drawable).我实际上使用过:`Drawable drawable = VectorDrawableCompat.create(getResources(),status.getIconResId(),wrapper.getTheme()); statusButton.setCompoundDrawablesRelativeWithIntrinsicBounds(null,drawable,null,null);` (8认同)
  • `setCompoundDrawablesWithIntrinsicBounds` 的 minSdk 是 **17**。否则这很好用。 (2认同)
  • 它的 minSdk 是 1 而不是 17,你可能看起来很相似。setCompoundDrawablesWithIntrinsicBounds =&gt; minSdk 1; setCompoundDrawablesRelativeWithIntrinsicBounds =&gt; minSdk 17 (2认同)

Dav*_*and 60

为了补充这里的一些答案:你可以将VectorDrawable作为drawableLeft(等)工作,但它取决于支持库版本,它需要付出代价.

它在哪些情况下有效?我已经使这个图表有所帮助(对支持库23.4.0有效 - 至少 - 25.1.0).

VectorDrawable cheatsheet

  • 很好,但是您应该将静态块中的方法名称更正为`setCompatVectorFromResourcesEnabled`。 (2认同)

Sak*_*boy 14

没有其他答案有效,这里是我如何添加VectorDrawablea TextView,你应该VectorDrawableCompat.create()在处理VectorDrawables下面时使用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);
}
Run Code Online (Sandbox Code Playgroud)

简短,甜美,至关重要!


小智 9

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

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


小智 9

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

写吧

<TextView
...
android:drawableRight="@{@drawable/ic_accessible_white_36px}"/>
Run Code Online (Sandbox Code Playgroud)

并将整个布局包装在一个<layout>标签中,所以基本上你的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>
Run Code Online (Sandbox Code Playgroud)

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

android {
    ....
    defaultConfig {
        dataBinding {
            enabled = true
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

编辑:

当然,如果你想使用矢量drawables pre-Lollipop你必须使用支持向量drawables

vectorDrawables.useSupportLibrary = true

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

android {
    ....
    defaultConfig {
        vectorDrawables.useSupportLibrary = true
        dataBinding {
            enabled = true
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

感谢rkmax的评论


Rah*_*rma 5

我迟到了回答这个问题,因为我迟迟没有回答这个问题.我使用TextView与svg/vector drawables有同样的问题.而不是制作自己的自定义drawable我能够用2行代码修复我的问题,如下所示:

Drawable drawableTop = AppCompatResources.getDrawable(view.getContext(), iconId);
view.setCompoundDrawablesWithIntrinsicBounds(null, drawableTop, null, null);
Run Code Online (Sandbox Code Playgroud)

希望它会帮助你.


Ami*_*kur 5

我通过所有答案并使用最新的Android studio 3.0.1和appcompat支持库26.1.0,我可以保证这个工作正常.

在build.gradle(app)文件中

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

dependencies {
    implementation 'com.android.support:appcompat-v7:26.1.0'
}
Run Code Online (Sandbox Code Playgroud)

在Activity中,扩展AppcompatActivity包括这个外部方法,即静态块

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}  
Run Code Online (Sandbox Code Playgroud)

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

override fun onCreate() {
    super.onCreate()
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
}
Run Code Online (Sandbox Code Playgroud)

xml中的T​​extview

<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>
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

  • 如上所述,如果你直接使用vector xml作为drawableLeft你仍然会遇到这种崩溃或异常,因此解决方法是使用该向量xml作为textview的drawableLeft的选择器.用法你可以在编辑的答案中看到. (2认同)

che*_*tov 5

androidx.appcompat:appcompat:1.1.0开始,您可以使用

app:drawableLeftCompat
app:drawableStartCompat
...
Run Code Online (Sandbox Code Playgroud)