เป็นไปได้ไหมที่จะใช้ VectorDrawable ในปุ่มและ TextViews โดยใช้ android: DrawableRight


120

เมื่อฉันใช้เนื้อหา VectorDrawable ใน textview หรือ imageview ฉันพบปัญหารันไทม์เมื่อใช้ "android: DrawableRight" / "android: DrawableEnd" / "android: DrawableStart" / "android: DrawableLeft"

แอพจะคอมไพล์ได้ดีโดยไม่มีคำเตือนใด ๆ

ฉันใช้

  • Gradle 1.5
  • รองรับไลบรารี 23.2 ('com.android.support:appcompat-v7:23.2.0')

สิ่งที่ฉันได้พบคือฉันสามารถกำหนด SVG ใน Java โดยทางโปรแกรมได้โดยไม่เกิดปัญหาเช่นนี้

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

        }
    }

นี่คือเนื้อหา VectorDrawable ที่ไม่ได้แก้ไขจากไซต์ออกแบบวัสดุของ Google

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

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 เท่านั้น)
Phantômaxx

2
หากต้องการดูวิธีใช้ VectorDrawable กับ drawableLeft, drawableRight, drawableTop, drawableBottom ลองดูคำตอบนี้
Behzad Bahmanyar

ฉันพบว่าสิ่งนี้ใช้ได้กับฉัน: android.jlelse.eu/…
Huy Tower

คำตอบ:


186

เป็นไปได้ที่จะใช้ drawableRight และอื่น ๆ สำหรับเนื้อหา SVG?

ใช่

AppCompatTextView ขณะนี้สนับสนุนapp:drawableLeftCompat, app:drawableTopCompat, app:drawableRightCompat, app:drawableBottomCompat, app:drawableStartCompatและapp:drawableEndCompatภาพวาดสารประกอบสนับสนุน backported ประเภท drawable VectorDrawableCompatเช่น

รวมสิ่งนี้ไว้ในไฟล์ gradle ของคุณ

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

ในมุมมองข้อความของคุณคุณสามารถใช้ได้

app:drawableLeftCompat
app:drawableStartCompat

หากคุณมีปัญหาขณะใช้แอพ: drawableLeftCompat, app: drawableStartCompat ในปุ่มคุณจะต้องอัปเดตไลบรารีของคุณเป็น

androidx.appcompat: AppCompat: 1.2.0-alpha01

พวกเขามีข้อบกพร่อง

androidx.appcompat: AppCompat: 1.1.0-alpha01

คุณสามารถดูเอกสาร


หรือหากคุณยังไม่ต้องการอัปเดตให้ทำดังนี้

เนื่องจากดูเหมือนว่า Google จะไม่ดำเนินการใด ๆ เกี่ยวกับปัญหานี้ในเร็ว ๆ นี้ฉันจึงต้องหาวิธีแก้ปัญหาที่สามารถใช้ซ้ำได้สำหรับแอปทั้งหมดของฉัน:

  1. ขั้นแรกให้เพิ่มแอตทริบิวต์TextView ที่กำหนดเองในไฟล์ attrs.xml ของแอปของคุณ"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 -->
        />
    • คุณสามารถทำสิ่งที่คล้ายกันกับปุ่ม , EditTextและRadioButtonเพราะพวกเขามาจาก TextView

หวังว่านี่จะช่วยได้ :)


4
คำตอบที่มีประโยชน์มาก อย่างไรก็ตามฉันขอแนะนำให้อ่านคำตอบที่สมบูรณ์ของ Dadouด้วย การลบออกvectorDrawables { useSupportLibrary = true }จากbuild.gradleคำตอบที่แนะนำนั้นใช้ได้ผลกับฉัน
แซม

ฉันทำอย่างนั้นและตอนนี้ฉันมีปัญหาต่อไปนี้: เมื่อฉันแนบ onclick ใน XML ฉันได้รับข้อผิดพลาดต่อไปนี้: java.lang.NoSuchMethodException: onClick [class android.view.View]
Ramdane Oualitsen

3
ฉันไม่เห็นด้วยกับการลบvectorDrawables useSupportLibrary = trueเส้นออกจาก gradle เมื่อคุณลบออกคุณยังคงสามารถใส่เวกเตอร์ไว้ในมุมมองของคุณได้ แต่จะปรับขนาดในลักษณะเดียวกับ png ซึ่งหมายความว่าจะถูกยืดออกและกลายเป็นเม็ดเล็ก ๆ หากคุณต้องการให้อุปกรณ์ที่ต่ำกว่า 5.0 / API21 ปรับขนาดเวกเตอร์ได้อย่างถูกต้องเพื่อให้ดูคมชัดคุณต้องใช้บรรทัดนั้นในไฟล์ gradle การใส่บรรทัดนั้นจะเรียกใช้ IDE เพื่อค้นหาพื้นที่ที่คุณใช้เวกเตอร์ไม่ถูกต้องจากนั้นคุณต้องใช้app:srcCompatผ่าน XML หรือตั้งค่าด้วยรหัสด้วยVectorDrawableCompat.create()
Heinous Games

จะเพิ่มapp:drawableEndCompatการรองรับ RTL ที่ดีขึ้นได้อย่างไร? สาเหตุsetCompoundDrawablesRelativeWithIntrinsicBoundsต้องการ API ระดับ 17 เป็นอย่างน้อย
Dr.jacky

1
สิ่งที่เกี่ยวกับการตั้งค่า drawable โดยทางโปรแกรม?
นักพัฒนา Android

77

วิธีแก้ปัญหานี้ไม่ถูกต้องอีกต่อไป จากเวอร์ชัน 23.3.0 vector drawables สามารถโหลดผ่าน 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>

นี้ใช้งานได้ดี ขอบคุณ .. แต่ดูเหมือนว่าคุณไม่สามารถอ้างถึง SVG ใน "android: drawableXXXXX" ได้โดยตรงคุณต้องห่อเป็นอย่างอื่น
angryITguy

1
ใช่. คุณไม่สามารถใช้งานได้โดยตรง เป็นแอปเท่านั้น: srcCompat หรือรวมหรือโดยทางโปรแกรม สิ่งนี้อธิบายไว้ที่นี่: android-developers.blogspot.ru/2016/02/…
Alexandr Shutko

อ่า .. ขอบคุณ .. ฉันเห็นย่อหน้าที่คุณอ้างถึง ดังนั้นมันยังคงเป็นข้อผิดพลาดถ้าพวกเขาบอกคุณว่าจะไม่ทำ? ;)
angryITguy

1
ฉันคิดว่ามันเกี่ยวกับความเข้ากันได้แบบย้อนหลัง ดูเหมือนว่าจะมีปัญหาในการรับการสนับสนุน svg เต็มรูปแบบดังนั้นพวกเขาจึงทำการแก้ปัญหาบางอย่าง ...
Alexandr Shutko

2
@HarishGyanani จากเวอร์ชันรองรับ 23.3.0 ไม่รองรับอีกต่อไป คุณต้องเพิ่มคำสั่งเพิ่มเติมในกิจกรรมของคุณ: static {if (Build.VERSION.SDK_INT <Build.VERSION_CODES.LOLLIPOP) {AppCompatDelegate.setCompatVectorFromResourcesEnabled (true); }}
ป้องเหงียน

75

วิธีที่ดีที่สุดที่ฉันพบ:

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

9
ณ วันที่ 25/8/17 นี่เป็นสิ่งเดียวที่เหมาะกับฉัน (ตั้งค่าการวาดแบบเป็นโปรแกรม) ฉันใช้จริง:Drawable drawable = VectorDrawableCompat.create(getResources(), status.getIconResId(), wrapper.getTheme()); statusButton.setCompoundDrawablesRelativeWithIntrinsicBounds(null, drawable, null, null);
saiyancoder

2
minSdk สำหรับsetCompoundDrawablesWithIntrinsicBoundsเป็น17 มิฉะนั้นจะใช้งานได้ดี
Victor Rendina

1
minSdk ของมันคือ 1 ไม่ใช่ 17 คุณอาจดูเหมือน apis ที่คล้ายกัน setCompoundDrawablesWithIntrinsicBounds => minSdk 1; setCompoundDrawablesRelativeWithIntrinsicBounds => minSdk 17
正宗白布鞋

ทางออกที่ดีที่สุดสำหรับการตั้งค่าโดยใช้โปรแกรม +1
Woton Sampaio

ฉันใช้สิ่งนี้กับ BindingAdapters และทำงานได้อย่างมีประสิทธิภาพขอบคุณ!
Ric17101

61

เพื่อเติมเต็มคำตอบบางส่วนที่นี่คุณสามารถรับ VectorDrawable เพื่อทำงานเป็นdrawableLeft(ฯลฯ ) ได้ แต่ขึ้นอยู่กับเวอร์ชัน Support Library และมาพร้อมกับราคา

มันได้ผลในกรณีใดบ้าง? ฉันทำแผนภาพนี้เพื่อช่วย (ใช้ได้กับ Support Library 23.4.0 ถึง - อย่างน้อย - 25.1.0)

Cheatsheet VectorDrawable


2
ดีมาก แต่คุณควรแก้ไขชื่อเมธอดในบล็อกแบบคงที่เป็นsetCompatVectorFromResourcesEnabled
Vikas Patidar

1
setCompatVectorFromResourcesEnabled โซลูชันไม่ทำงานบน 25.3.1 น่าเสียดาย
Ilja S.

From 23.3.0 version vector drawables can only be loaded via app:srcCompat or setImageResource()ดังนั้นโซลูชันนี้จึงเลิกใช้งานและไม่สามารถใช้งานได้
25

การเปิดใช้งานsetCompatVectorFromSourcesEnabled(true)ทำให้สามารถโหลด vectordrawables ในandroid:backgroundAndroid 4.x. ขอบคุณมาก! (คุณต้องรวมเวกเตอร์จริงในรายการเลเยอร์รายการเดียว)
Peterdk

14

คำตอบอื่น ๆ ไม่ได้ผลนี่คือวิธีที่ฉันเพิ่ม a VectorDrawableใน a 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);
}

สั้นหวานและตรงประเด็น!


สิ่งนี้ใช้ได้กับ Android P และขั้นต่ำ API ระดับ 26 (เป้าหมาย 28)
MiStr

@MiStr - มันยังเข้ากันได้แบบย้อนหลัง :)
Sakiboy

9

จาก Google: สำหรับ Android Support Library 23.3.0 การรองรับ vector drawables สามารถโหลดผ่านแอพ: srcCompat หรือ setImageResource () เท่านั้น ..

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


1
นั่นหมายความว่าตอนนี้ไม่มีทางแก้
Killer

ลองรวมเวกเตอร์ที่วาดได้ลงในรายการเลเยอร์หรือตัวเลือก: <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>
Null Pointer Exception

9

เป็นไปได้ที่จะตั้งค่า vector drawables ใน xml โดยตรง แต่คุณได้รวมกรอบการผูกข้อมูลไว้ด้วย

แค่เขียน

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

และรวมเค้าโครงทั้งหมดของคุณใน<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>

ในการเปิดใช้งานกรอบการผูกข้อมูลเพียงแค่เพิ่ม

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

คุณไม่จำเป็นต้องใช้คุณสมบัติอื่น ๆ ของไลบรารีที่มีผลผูกพัน

แก้ไข:

แน่นอนถ้าคุณต้องการใช้ vector drawables pre-Lollipop คุณต้องเปิดใช้งานการรองรับ vector drawables โดยใช้

vectorDrawables.useSupportLibrary = true

ดังนั้นbuild.gradleความต้องการของคุณ2 คำสั่งใหม่:

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

ขอบคุณrkmaxสำหรับข้อสังเกต


นี่เป็นความคิดที่ดี แต่คุณต้องเขียนอะแดปเตอร์ที่มีผลผูกพันเพื่อให้ใช้งานได้ นี่คือตัวอย่างการทำงาน: gist.github.com/lisawray/78c33f76809d2bcbbec9983e2c141a70
BladeCoder

1
ฉันต้องบอกว่าสิ่งนี้ใช้ได้กับฉัน แต่คุณต้องเปิดใช้งานvectorDrawables.useSupportLibraryบน app / build.gradle และเพิ่ม AppCompatDelegate.setCompatVectorFromResourcesEnabled (true) ในกิจกรรม
rkmax

ฉันลืมเพิ่ม defaultConfig build.gradleซึ่งอาจเป็นสาเหตุว่าทำไมมันไม่ทำงาน
Hans M

ขอบคุณ - คุณเป็นผู้ช่วยชีวิต!
รถตู้

นี่คือคำตอบที่ประเมินไม่ได้!
DYS

6

ฉันตอบทุกคำตอบและใช้ 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)
}

Textview ใน 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?
Divers

คุณสามารถแสดงวิธีที่คุณใช้drawableRightสำหรับTextViewในรูปแบบ XML?
นักดำน้ำ

2
เช่นเดียวกับที่กล่าวมาข้างต้นหากคุณใช้ vector xml โดยตรงเป็น drawableLeft u ยังคงได้รับข้อผิดพลาดหรือข้อยกเว้นนี้ดังนั้นวิธีแก้ปัญหาคือใช้เวกเตอร์ xml นั้นเป็นตัวเลือกสำหรับ drawableLeft สำหรับ Textview การใช้งานคุณสามารถดูได้ในคำตอบที่แก้ไข
Amit Tumkur

1
มันจะไม่ทำงานคุณไม่สามารถใช้ vector drawable สำหรับ TextView โดยตรงใน xml
25

ทดสอบใน API 19 และ 20 ฉันใช้ AppCompatDelegate.setCompatVectorFromResourcesEnabled ในคลาสแอปพลิเคชันแทน ทำงานอย่างมีเสน่ห์!
แดง M


5

ฉันสายมากที่จะตอบคำถามนี้เนื่องจากฉันติดปัญหานี้จนดึก ฉันมีปัญหาเดียวกันกับ svg / vector drawables กับ TextView แทนที่จะสร้างแบบวาดเองของคุณเองฉันสามารถแก้ไขปัญหาของฉันด้วยโค้ด 2 บรรทัดดังต่อไปนี้:

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

หวังว่ามันจะช่วยคุณได้


ไม่สามารถใช้งานร่วมกับLอุปกรณ์ก่อน
Sakiboy

@Sakiboy ใช่แล้วเนื่องจากฉันใช้รหัสนี้กับ api ขั้นต่ำ 17.
Rahul Sharma

ใช้ไม่ได้กับVectorDrawablesอุปกรณ์ทั้งหมดที่ใช้ pre-L เพียงแค่พูด โปรดใช้ความระมัดระวังเมื่อใช้คำตอบนี้เนื่องจากมี API ที่ปลอดภัยกว่าให้ใช้
Sakiboy

4

ฉันได้ออกแบบไลบรารีเล็ก ๆ สำหรับสิ่งนี้ - textview-rich-drawable (นอกจากนี้ยังรองรับการกำหนดขนาดและการย้อมสีแบบ Compound-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" />

และการพึ่งพา

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

ใส่คำอธิบายภาพที่นี่


3

หากคุณใช้การผูกมีวิธีวิเศษอีกวิธีหนึ่งในการใช้เวกเตอร์แบบเดียวกันใน TextView ห่อพวกเขาเช่น:

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

มันจะใช้งานได้อย่างน่าอัศจรรย์ฉันไม่ได้ตรวจสอบสิ่งที่เกิดขึ้นเบื้องหลัง แต่ฉันเดาว่า TextView กำลังใช้getDrawableวิธีการจากAppCompatResourcesหรือคล้ายกัน


2

จากคำตอบของ Behzad Bahmanyar ฉันสังเกตเห็นว่าฉันไม่สามารถใช้คุณลักษณะปกติของ Android สำหรับไฟล์ png ปกติ:

android:drawableTop
android:drawableBottom
etc

เพราะมันจะถูกแทนที่ด้วย null ใน

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

2

ในไฟล์ 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]);
    } 
}

ใช้ (เมื่อ Databinding)

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

หรือ (ปกติ)

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

1

การใช้ Vector Drawables ใช้

Kotlin

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

ชวา

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

1

สำหรับการใช้งานร่วมกันได้ย้อนหลัง:

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

0

ฉันใช้ Binding Adapter เพื่อแก้ปัญหานี้

@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 ในการกำหนดค่าเริ่มต้นเป็นสิ่งจำเป็น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.