失迹的博客

Recent content on 失迹的博客

马上订阅 失迹的博客 RSS 更新: https://blog.reincarnatey.net/index.xml

踩坑记录 | Android中LayoutInflater读取attr颜色属性报错:Failed to resolve attribute at index 77: TypedValue{t=0x2/d=0x7f030107 a=-1}

2023年1月22日 16:20

踩坑

背景

项目要适配夜间模式,因此要添加深色主题(Dark Theme),也就是Android开发中很常见的开发要求——多主题

在查找资料的时候发现多主题似乎在select和drawable上存在很大的坑,不过这里估计是因为使用了Androidx、AppCompat、Material3,所以并没有跳进去他们的坑,反倒是自己找了一处偏僻的小坑钻进去了。

发生这个问题的时候,我正在尝试使用Databinding获取自定义的Toast布局:

val binding = ToastBinding.inflate(LayoutInflater.from(context))

attrs.xml 添加自定义属性、在 theme 中赋值、在布局和 Drawable 中引用。

values/attrs.xml

<resources>
    <attr name="toastColor" format="reference|color" />
    ...
</resources>

values/themes.xml

<resources>
    <style name="AppTheme" parent="Theme.Material3.Light.NoActionBar">
        <item name="toastColor">@color/toast_light</item>
        ...
    </style>

    <style name="Theme.MyApp" parent="AppTheme" />
</resources>

drawable/check_circle.xml

<vector android:autoMirrored="false" android:height="24dp" android:viewportHeight="24"
    android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
    <path android:fillColor="?attr/toastIconColor" android:pathData="M10,17l-5,-5 1.41,-1.41L10,14.17l7.59,-7.59L19,8l-9,9z"/>
    <!-- 这是一个svg格式的矢量图,重要的是↑这个fillColor里引用了attr,后面的pathData是图片绘制路径 -->
</vector>

layout/my_toast.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <androidx.constraintlayout.widget.ConstraintLayout
        ...
        android:background="?attr/toastColor" >

        <ImageView
            ...
            android:src="@drawable/check_circle" />

        <TextView
            ...
            android:textColor="?attr/toastTextColor" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

编译时一切顺利,然后一运行,问题就嘎嘎找上门了……

问题描述

正如题目所说,运行时报了以下错误:

Failed to resolve attribute at index 77: TypedValue{t=0x2/d=0x7f030107 a=-1}

一开始我以为这里的 attribute 是属性的意思而不是特指 ?attr/ ,看了半天没看懂,于是上网一顿猛搜,发现跟Theme的自定义属性有关。

然而查来查去,都没有解决办法,勉强知道问题是出在控件没有正确地获取到 ?attr/ 的值

然而我适配多主题,靠的就是 attr 呀,那不完蛋了?

解决方法

在查找资料的过程中,我发现其他发生相似问题的,大多是 Application 没有设置好Theme、Activity 没有设置好Theme、Fragment 没有设置好Theme。一句话总结相同点,就是用于 LayoutInflater.from(context)context 没有正确地配置Theme

在尝试过各种办法都无效过后,走投无路的我大胆的猜测:难道是因为这个 View 没有配置好Theme吗?

于是我在 layout/my_toast.xml 的根布局的属性中加上了一行:

android:theme="@style/Theme.MyApp"

也就是变成下面的这个样子:

...
<androidx.constraintlayout.widget.ConstraintLayout
        ...
        android:theme="@style/Theme.MyApp"
        android:background="?attr/toastColor" >

        ...

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

然后问题就神奇的解决了。

既没有在 inflate 的时候报错,Drawable 也正常显示出来了。

分析原因

似乎由于传入 LayoutInflater.from(context)context 是一个我初始化时传入的 Application 对象,因此布局的View并没有自动获取到 AndroidManifest.xml 中的Theme配置。

而我们知道,attr 是与当前的 theme 完全关联的。...

剩余内容已隐藏

查看完整文章以阅读更多