【问题标题】:Image next to text?文字旁边的图片?
【发布时间】:2017-08-11 04:56:24
【问题描述】:

TL;DR:在 Textview 上使用简单的 android:drawableLeft 功能会导致崩溃

TextView 是 Android 最基本的视觉元素之一。那为什么它的最基本的功能不起作用呢?

https://developer.android.com/reference/android/widget/TextView.html#attr_android:drawableLeft

我的代码很简单——它是一个使用TextView 旁边的图像的自定义对话框:

<TextView
        android:text="Text next to check mark"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"          
        android:id="@+id/textView19"
        android:drawableLeft="@drawable/ic_check_circle_white_24dp"
        android:textSize="24sp"
        android:textStyle="normal|bold"/>

代码在可视化编辑器上提供了惊人的结果:

但当程序实际执行时,简单的android:drawableLeft 功能会使应用程序崩溃:

android.view.InflateException: Binary XML file line #64: Error inflating class TextView

Full stacktrace


我尝试像这样打开对话框:

dialog = new Dialog(this,R.style.Theme_AppCompat_Light_Dialog_Alert );
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(R.layout.premium_dialog);
dialog.setCanceledOnTouchOutside(false);

dialog.getWindow().setLayout((int) (getResources().getDisplayMetrics().widthPixels * 0.90), (int) (getResources().getDisplayMetrics().heightPixels * 0.90));

dialog.show();

为什么这种基本功能会导致InflateException? (我知道是 drawableLeft 函数导致了问题,因为当我删除 TextView 时,错误消失了)

【问题讨论】:

  • 从您的完整堆栈跟踪中,您在哪里使用过Caused by: android.content.res.Resources$NotFoundException: File **res/drawable/abc_dialog_material_background.xml** from color state list resource ID #0x7f020011
  • 你不能直接在Textview中使用vectordrwable,API较低。创建 CustomTextview 以支持 Lower API 中的矢量

标签: java android xml algorithm text


【解决方案1】:

在 setContentView 上试试这个

LayoutInflater layoutInflater = LayoutInflater.from(context);
View promptView = layoutInflater.inflate(R.layout.premium_dialog, null);
dialog.setContentView(promptView);

【讨论】:

    【解决方案2】:

    在底层 API 中为 VectorDrawable 创建一个 CustomTextView。

    按如下方式初始化自定义 Textview 的属性:

    private void initAttrs(Context context, AttributeSet attrs) {
            if (attrs != null) {
                TypedArray attributeArray = context.obtainStyledAttributes(attrs,R.styleable.CustomTextView);
                //for font
                String fontName = attributeArray.getString(R.styleable.CustomTextView_font);
    
                try {
                    if (fontName != null) {
                        Typeface myTypeface = Typeface.createFromAsset(getContext().getAssets(), "fonts/" + fontName);
                        setTypeface(myTypeface);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
    
                Drawable drawableLeft = null;
                Drawable drawableRight = null;
                Drawable drawableBottom = null;
                Drawable drawableTop = null;
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    drawableLeft = attributeArray.getDrawable(R.styleable.CustomTextView_drawableLeftCompat);
                    drawableRight = attributeArray.getDrawable(R.styleable.CustomTextView_drawableRightCompat);
                    drawableBottom = attributeArray.getDrawable(R.styleable.CustomTextView_drawableBottomCompat);
                    drawableTop = attributeArray.getDrawable(R.styleable.CustomTextView_drawableTopCompat);
                } else {
                    final int drawableLeftId = attributeArray.getResourceId(R.styleable.CustomTextView_drawableLeftCompat, -1);
                    final int drawableRightId = attributeArray.getResourceId(R.styleable.CustomTextView_drawableRightCompat, -1);
                    final int drawableBottomId = attributeArray.getResourceId(R.styleable.CustomTextView_drawableBottomCompat, -1);
                    final int drawableTopId = attributeArray.getResourceId(R.styleable.CustomTextView_drawableTopCompat, -1);
    
                    if (drawableLeftId != -1)
                        drawableLeft = AppCompatResources.getDrawable(context, drawableLeftId);
                    if (drawableRightId != -1)
                        drawableRight = AppCompatResources.getDrawable(context, drawableRightId);
                    if (drawableBottomId != -1)
                        drawableBottom = AppCompatResources.getDrawable(context, drawableBottomId);
                    if (drawableTopId != -1)
                        drawableTop = AppCompatResources.getDrawable(context, drawableTopId);
                }
                setCompoundDrawablesWithIntrinsicBounds(drawableLeft, drawableTop, drawableRight, drawableBottom);
                attributeArray.recycle();
            }
        }
    

    您的自定义 Styleable 相同。

    <attr name="drawableLeftCompat" format="reference" />
        <attr name="drawableRightCompat" format="reference" />
        <attr name="drawableTopCompat" format="reference" />
        <attr name="drawableBottomCompat" format="reference" />
    
        <declare-styleable name="CustomTextView">
            <attr name="font" format="string" />
            <attr name="drawableLeftCompat" />
            <attr name="drawableRightCompat" />
            <attr name="drawableTopCompat" />
            <attr name="drawableBottomCompat" />
        </declare-styleable>
    

    【讨论】:

    • 为什么?我只是处理来自 (material.io/icons/#ic_check_circle) 的简单 .png,而不是向量!如果基本功能只是使用drawableLeft,为什么我必须实现这个方法?
    • @Ruchir Banronia 如果您的drawableLeft 不是Vector (更受欢迎和可扩展的),则无需创建自定义Textview 来访问.png 文件。但是从您的 stackTrace 中可以看出您正在尝试访问矢量 drawble。
    • 这就是我如此困惑的原因。我正在使用此处的 .png 文件:material.io/icons/#ic_check_circle。还有其他建议吗?
    【解决方案3】:

    android:drawableLeft(和上/右/下)不能在旧 API 级别上使用矢量绘图。要么使用 .png 可绘制对象,要么在 TextView 旁边使用带有 ImageView 的 LinearLayout。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-05-06
    • 1970-01-01
    • 1970-01-01
    • 2018-02-26
    • 2021-01-26
    • 1970-01-01
    • 2019-07-30
    相关资源
    最近更新 更多