Có thể sử dụng VectorDrawable trong Buttons và TextViews bằng android: DrawableRight không?


120

Khi tôi sử dụng nội dung VectorDrawable trong chế độ xem văn bản hoặc chế độ xem hình ảnh, tôi gặp sự cố thời gian chạy khi sử dụng "android: DrawableRight" / "android: DrawableEnd" / "android: DrawableStart" / "android: DrawableLeft".

Ứng dụng sẽ biên dịch tốt mà không có bất kỳ cảnh báo nào.

tôi đang dùng

  • Gradle 1.5
  • Thư viện hỗ trợ 23.2 ('com.android.support:appcompat-v7:23.2.0')

Mặc dù vậy, những gì tôi đã tìm thấy là tôi có thể gán SVG theo lập trình trong Java mà không gặp sự cố như thế này.

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

(Tôi nghi ngờ đây là lỗi thư viện hỗ trợ cho 23.2.)

Nhưng liệu có thể sử dụng drawableRight, v.v. cho nội dung SVG không?

Đây là bố cục của tôi

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

Đây là hoạt động của tôi

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

        }
    }

Đây là nội dung VectorDrawable chưa được sửa đổi từ trang web material design của 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>

Đây là ứng dụng build.gradle của tôi

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

Đây là vụ tai nạn. (Lưu ý lỗi thổi phồng tham chiếu chế độ xem văn bản.)

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

Không, bạn không thể, vì tệp SVG nguyên bản không được hỗ trợ . Thay vào đó, bạn phải sử dụng VectorDrawable (chỉ sử dụng một tập hợp con của thông số SVG).
Phantômaxx

2
Để xem cách sử dụng VectorDrawable với drawableLeft, drawableRight, drawableTop, drawableBottom kiểm tra Câu trả lời này
Behzad Bahmanyar

Tôi tìm thấy cái này phù hợp với tôi: android.jlelse.eu/…
Huy Tower

Câu trả lời:


186

có thể sử dụng drawableRight, v.v. cho nội dung SVG không?

Đúng

AppCompatTextView tại hỗ trợ app:drawableLeftCompat, app:drawableTopCompat, app:drawableRightCompat, app:drawableBottomCompat, app:drawableStartCompatapp:drawableEndCompatdrawables hợp chất, hỗ trợ backported loại drawable như VectorDrawableCompat.

Bao gồm cái này trong tệp gradle của bạn

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

Trong chế độ xem văn bản của bạn, bạn có thể sử dụng

app:drawableLeftCompat
app:drawableStartCompat

Nếu bạn gặp sự cố khi sử dụng app: drawableLeftCompat, app: drawableStartCompat trong các nút, bạn sẽ cần cập nhật thư viện của mình lên

androidx.appcompat: appcompat: 1.2.0-alpha01

họ có một lỗi trên

androidx.appcompat: appcompat: 1.1.0-alpha01

bạn có thể nhìn thấy tài liệu


Hoặc nếu bạn chưa muốn cập nhật, hãy:

Vì có vẻ như Google sẽ không sớm làm gì với vấn đề này, nên tôi đã phải đưa ra một giải pháp có thể tái sử dụng chắc chắn hơn cho tất cả các ứng dụng của mình:

  1. Trước tiên, hãy thêm các thuộc tính TextView tùy chỉnh trong tệp attrs.xml của ứng dụng "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. Sau đó, tạo lớp TextView tùy chỉnh như sau:

    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. Giờ đây, bạn có thể dễ dàng sử dụng nó trong bất kỳ bố cục nào bằng các thuộc tính tùy chỉnh của mình:

    <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 -->
        />
    • Bạn có thể làm điều tương tự với Button , EditTextRadioButton vì chúng bắt nguồn từ TextView

Hi vọng điêu nay co ich :)


4
Câu trả lời rất hữu ích. Dù sao, tôi cũng khuyên bạn nên đọc câu trả lời rất đầy đủ của Dadou . Xóa vectorDrawables { useSupportLibrary = true }khỏi của tôi build.gradlevì câu trả lời đó gợi ý đã hiệu quả với tôi.
Sam

Tôi đã làm điều đó và tôi có bây giờ vấn đề sau đây: khi tôi gắn onclick trong XML tôi nhận được lỗi sau: java.lang.NoSuchMethodException: onClick [lớp android.view.View]
Ramdane Oualitsen

3
Tôi không đồng ý với việc loại bỏ vectorDrawables useSupportLibrary = truedòng khỏi gradle. Khi bạn xóa nó, bạn vẫn có thể đặt các vectơ bên trong khung nhìn của mình, nhưng chúng thay đổi kích thước giống như pngs, có nghĩa là chúng sẽ bị kéo căng và trở nên sần sùi. Nếu bạn muốn các thiết bị dưới 5.0 / API21 thực sự thay đổi kích thước các vectơ một cách chính xác để chúng trông sắc nét, bạn phải sử dụng dòng đó bên trong tệp gradle. Đưa dòng trong gọi IDE để tìm những vùng mà bạn đang sử dụng vectơ không đúng và sau đó bạn phải sử dụng app:srcCompatthông qua XML hoặc thiết lập nó qua mã vớiVectorDrawableCompat.create()
ghê tởm Games

Làm thế nào để thêm app:drawableEndCompatđể hỗ trợ RTL tốt hơn? Nguyên nhân setCompoundDrawablesRelativeWithIntrinsicBoundscần ít nhất API cấp 17.
Dr.jacky

1
Điều gì về thiết lập có thể vẽ theo chương trình?
nhà phát triển android

77

Giải pháp này không còn đúng nữa. Từ phiên bản 23.3.0 các tệp có thể vẽ vector chỉ có thể được tải qua ứng dụng: srcCompat hoặc setImageResource ()

Cố gắng bọc vectơ có thể vẽ của bạn vào danh sách lớp hoặc bộ chọn:

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

Điều này hoạt động tốt. Cảm ơn .. Nhưng có vẻ như bạn không thể tham chiếu trực tiếp đến SVG trong "android: drawableXXXXX", bạn phải bọc nó trong một thứ khác.
tức giậnITguy

1
Đúng. Bạn không thể sử dụng nó trực tiếp. Chỉ dưới dạng ứng dụng: srcCompat hoặc được gói hoặc theo chương trình. Điều này đã được mô tả ở đây: android-developers.blogspot.ru/2016/02/...
Alexandr Shutko

Ahh .. cảm ơn .. Tôi có thể thấy đoạn bạn đang đề cập đến. Vì vậy, nó vẫn là một lỗi nếu họ nói với bạn không làm điều đó? ;)
tức giậnITguy

1
Tôi nghĩ rằng đó là tất cả về khả năng tương thích ngược. Dường như có một số vấn đề để có được sự ủng hộ svg đầy đủ, vì vậy họ thực hiện một số biện pháp khắc phục ...
Alexandr Shutko

2
@HarishGyanani từ phiên bản hỗ trợ 23.3.0, nó không được hỗ trợ lâu hơn. Bạn phải thêm lệnh khác trong hoạt động của mình: static {if (Build.VERSION.SDK_INT <Build.VERSION_CODES.LOLLIPOP) {AppCompatDelegate.setCompatVectorFromResourcesEnabled (true); }}
Cuong Nguyen

75

Cách tốt nhất tôi đã tìm thấy:

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

9
Kể từ ngày 25/8/17, đây là thứ duy nhất phù hợp với tôi (thiết lập có thể vẽ theo lập trình). Tôi thực sự được sử dụng:Drawable drawable = VectorDrawableCompat.create(getResources(), status.getIconResId(), wrapper.getTheme()); statusButton.setCompoundDrawablesRelativeWithIntrinsicBounds(null, drawable, null, null);
saiyancoder

2
minSdk cho setCompoundDrawablesWithIntrinsicBounds17 . Nếu không, điều này hoạt động tuyệt vời.
Victor Rendina

1
MinSdk của nó là 1 chứ không phải 17, bạn có thể nhìn giống apis. setCompoundDrawablesWithIntrinsicBounds => minSdk 1; setCompoundDrawablesRelativeWithIntrinsicBounds => minSdk 17
正宗 白 布鞋

Giải pháp tốt nhất cho việc thiết lập chương trình, 1
Woton Sampaio

Tôi đã sử dụng cái này với BindingAdapters và hoạt động hiệu quả, cảm ơn!
Ric17101

61

Để bổ sung một số câu trả lời ở đây: bạn có thể nhận VectorDrawable để hoạt động nhưdrawableLeft (v.v.) nhưng nó phụ thuộc vào phiên bản Thư viện hỗ trợ và nó đi kèm với một mức giá.

Nó hoạt động trong những trường hợp nào? Tôi đã tạo sơ đồ này để trợ giúp (hợp lệ cho Thư viện hỗ trợ 23.4.0 đến - ít nhất - 25.1.0).

VectorDrawable cheatsheet


2
Thật tuyệt vời nhưng bạn nên sửa tên phương pháp trong khối tĩnh đểsetCompatVectorFromResourcesEnabled
Vikas Patidar

1
setCompatVectorFromResourcesEnabled giải pháp không hoạt động trên 25.3.1, không may
Ilja S.

From 23.3.0 version vector drawables can only be loaded via app:srcCompat or setImageResource()vì vậy giải pháp này không được dùng nữa và sẽ không hoạt động
25

kích hoạt setCompatVectorFromSourcesEnabled(true)giúp bạn có thể tải vectordrawables android:backgroundtrên Android 4.x. Vì vậy, cảm ơn! (Bạn cần phải bọc vector thực tế trong một danh sách lớp mục duy nhất)
Peterdk

14

Không có câu trả lời nào khác hoạt động, đây là cách tôi đã thêm a VectorDrawablevào a TextView, bạn nên sử dụng VectorDrawableCompat.create()khi giải quyết VectorDrawablesbên dưới 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);
}

Ngắn, ngọt ngào, và cho điểm!


Điều này hoạt động với Android P và API tối thiểu cấp 26 (mục tiêu 28)
MiStr 21/09/18

@MiStr - Nó cũng tương thích ngược :)
Sakiboy 22/09/18

9

Từ Google: Kể từ Thư viện hỗ trợ Android 23.3.0, chỉ có thể tải các tệp có thể kéo vectơ hỗ trợ qua ứng dụng: srcCompat hoặc setImageResource () ..

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


1
điều đó có nghĩa là không có giải pháp nào cho bây giờ
Killer

Cố gắng bọc vectơ có thể vẽ của bạn vào danh sách lớp hoặc bộ chọn: <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

Có thể đặt trực tiếp các tệp có thể kéo vectơ trong xml, nhưng bạn đã bao gồm khung liên kết dữ liệu.

Chỉ viết

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

và bọc toàn bộ bố cục của bạn trong một <layout>thẻ, vì vậy về cơ bản xml của bạn sẽ giống như sau:

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

Để kích hoạt khung liên kết dữ liệu, chỉ cần thêm

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

Bạn không phải sử dụng bất kỳ tính năng nào khác của thư viện ràng buộc

BIÊN TẬP:

Tất nhiên, nếu bạn muốn sử dụng các bảng vẽ vector trước Lollipop, bạn phải bật các bảng vẽ vector hỗ trợ bằng cách sử dụng

vectorDrawables.useSupportLibrary = true

Vì vậy, bạn build.gradlecần 2 lệnh mới:

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

cảm ơn rkmax cho nhận xét


Đây là một ý tưởng hay, nhưng bạn cần viết một bộ điều hợp ràng buộc để điều này hoạt động. Dưới đây là một ví dụ làm việc: gist.github.com/lisawray/78c33f76809d2bcbbec9983e2c141a70
BladeCoder

1
Tôi phải nói rằng công trình này cho tôi nhưng bạn phải kích hoạt vectorDrawables.useSupportLibrarytrên ứng dụng / build.gradle và cũng thêm AppCompatDelegate.setCompatVectorFromResourcesEnabled (true) vào hoạt động
rkmax

Tôi đã quên thêm defaultConfig trong build.gradleđó có thể là lý do tại sao nó không hoạt động
Hans M

Cảm ơn - bạn là một người tiết kiệm cuộc sống!
Văn

Đây là một câu trả lời được đánh giá thấp!
DYS

6

Tôi đã xem qua tất cả các câu trả lời và sử dụng Android studio 3.0.1 mới nhất và Thư viện hỗ trợ AppCompat 26.1.0. Tôi có thể đảm bảo rằng điều này hoạt động tốt.

Trong tệp build.gradle (app)

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

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

Và trong Activity mở rộng AppcompatActivitybao gồm các phương thức bên ngoài này, tức là một statickhối

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}  

hoặc nếu bạn muốn điều này được áp dụng cho toàn bộ ứng dụng, chỉ cần đưa dòng này vào bên trong lớp mở rộng Applicationlớp

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

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

Hoạt động tốt trên API nào? Bạn đã thử vào 19 hay 20?
Thợ lặn

Bạn có thể chỉ ra cách bạn sử dụng drawableRightcho TextViewtrong XML không?
Thợ lặn

2
như một số đề cập ở trên, nếu bạn sử dụng vector xml trực tiếp dưới dạng drawableLeft, bạn vẫn gặp sự cố hoặc ngoại lệ này, do đó, cách giải quyết là sử dụng vector xml đó làm bộ chọn cho drawableLeft cho Textview. Cách sử dụng bạn có thể xem trong câu trả lời đã chỉnh sửa.
Amit Tumkur

1
nó sẽ không hoạt động, bạn không thể sử dụng vector có thể vẽ được cho TextView trực tiếp trong xml
user25

Kiểm tra nó trong API 19 và 20. Thay vào đó, tôi đã sử dụng AppCompatDelegate.setCompatVectorFromResourcesEnabled trong lớp ứng dụng. Làm việc như một cái duyên!
Red M


5

Tôi quá muộn để trả lời câu hỏi này vì tôi đã bị mắc kẹt với vấn đề này. Tôi đã gặp vấn đề tương tự với các tệp có thể kéo svg / vector với TextView. Thay vì tạo tùy chỉnh có thể vẽ của riêng bạn, tôi có thể khắc phục sự cố của mình bằng 2 dòng mã như sau:

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

Hy vọng nó sẽ giúp bạn ra ngoài.


Không tương thích với các Lthiết bị trước .
Sakiboy

@Sakiboy Đúng vậy, vì tôi đang sử dụng mã này với api tối thiểu là 17.
Rahul Sharma

Không hoạt động với VectorDrawablestất cả các thiết bị chạy trước L, chỉ sayin. Hãy thận trọng khi sử dụng câu trả lời này, vì có những API chính xác hơn an toàn hơn để sử dụng.
Sakiboy

4

Tôi đã thiết kế một thư viện nhỏ cho việc này - textview-rich-drawable (nó cũng hỗ trợ xác định kích thước và pha màu của 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" />

Và sự phụ thuộc

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

nhập mô tả hình ảnh ở đây


3

Nếu bạn đang sử dụng ràng buộc, có một cách kỳ diệu khác để có cùng cách tiếp cận để sử dụng vectơ trong TextView. Bao bọc chúng như:

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

Điều đó sẽ hoạt động một cách kỳ diệu, tôi chưa điều tra những gì đang xảy ra đằng sau hậu trường, nhưng tôi đoán TextView đang sử dụng getDrawablephương pháp từ AppCompatResourceshoặc tương tự.


2

Dựa trên câu trả lời của Behzad Bahmanyar , tôi nhận thấy rằng tôi không thể sử dụng các thuộc tính bình thường của android cho các tệp png bình thường:

android:drawableTop
android:drawableBottom
etc

bởi vì nó sẽ được thay thế bằng null trong

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

nếu app:drawableTopCompatkhông được đặt, nhưngandroid:drawableTop là (ví dụ).

Đây là giải pháp đầy đủ:

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

Điều này nên được chấp nhận câu trả lời. hoạt động với tệp png bình thường và các thuộc tính drawableTop, drawableBottom. Câu trả lời được chấp nhận không hoạt động với tệp png và các thuộc tính drawableTop, drawableBottom.
Bhargav Pandya

2

Trong tệp 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]);
    } 
}

sử dụng (Khi Databinding)

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

Hoặc (Bình thường)

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

1

Sử dụng Vector Drawables sử dụng

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

Để sử dụng tương thích ngược:

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

0

Tôi đang sử dụng bộ điều hợp Binding để giải quyết vấn đề này

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

và cũng sử dụng theo cách này trong bố cục của tôi

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

có lẽ vectorDrawables.useSupportLibrary = true trong cấu hình mặc định là cần thiết

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.