【问题标题】:Library's style attributes have no values even though they are explicitly set库的样式属性没有值,即使它们被显式设置
【发布时间】:2018-05-09 14:15:52
【问题描述】:

我创建了一个带有自定义视图的库,该视图在创建时会扩展布局。布局中的视图使用style="?attr/labelStyle" 或任何其他属性设置样式。

该属性被声明为库的attrs.xml:

<attr name="myViewStyle" format="reference"/>

<declare-styleable name="MyView">
    <attr name="labelStyle" format="reference|color"/>
</declare-styleable>

我在库的styles.xml 中为这个属性设置了一个默认值:

<style name="MyViewStyle">
    <item name="labelStyle">@style/LabelStyle</item>
</style>

<style name="LabelStyle">
    <item name="android:textColor">?android:attr/textColorPrimary</item>
    <item name="...">...</item>
</style>

最后在图书馆的themes.xml:

<style name="MyViewStyleLight" parent="Theme.AppCompat.Light">
    <item name="myViewStyle">@style/MyViewStyle</item>
</style>

现在这是库的默认样式,但它在主项目styles.xml中被覆盖

<style name="AppTheme" parent="Theme.AppCompat.Light">
    <item name="myViewStyle">@style/MyViewStyleCustom</item>
</style>

<style name="MyViewStyleCustom" parent="MyViewStyleLight">
    <item name="android:textColor">@color/gray</item>
    <item name="...">...</item>
</style>

自定义视图代码:

public MyView(Context context) {
    this(context, null, R.attr.myViewStyle, 0);
}

public MyView(Context context, @Nullable AttributeSet attrs) {
    this(context, attrs, R.attr.myViewStyle, 0);
}

public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    this(context, attrs, defStyleAttr, 0);
}

public MyView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(createThemeWrapper(context, R.attr.myViewStyle, R.style.MyViewStyleLight),
            attrs, defStyleAttr, defStyleRes);
    initLayout();
}

private static Context createThemeWrapper(Context context, int styleAttr, int defaultStyle) {
    final TypedArray ta = context.obtainStyledAttributes(new int[]{styleAttr});
    int style = ta.getResourceId(0, defaultStyle);
    ta.recycle();
    return new ContextThemeWrapper(context, style);
}

private void initLayout() {
    LayoutInflater inflater = LayoutInflater.from(getContext());
    inflater.inflate(R.layout.my_view, this);
    ...
}

我在下面解释了 ContextThemeWrapper。现在应用程序在布局膨胀的那一行崩溃。这是崩溃日志的重要部分:

android.view.InflateException: Binary XML file line #0: Binary XML file line #0: Error inflating class com.example.MyView
      at android.view.LayoutInflater.inflate(LayoutInflater.java:539)
      at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
      [...]
    Caused by: java.lang.UnsupportedOperationException: Failed to resolve attribute at index 13: TypedValue{t=0x2/d=0x7f030057 a=-1}
      at android.content.res.TypedArray.getDrawable(TypedArray.java:867)
      [...]

布局充气器找不到属性的值。当我试图通过代码获取属性时,它什么也不返回。该属性实际上存在,只是它没有设置任何值,即使我已经明确设置了。

我应该如何设置我的库的样式?我几乎可以肯定,我所做的每一件事都与SublimePicker library 相同,但它就是行不通。与 ContextThemeWrapper 的部分有一点不同,但这可能不是问题。感觉好像在什么地方忘记了一个小东西,让属性没有价值,什么东西没有联系,不知道。

我知道这是一个很长的问题,但它不能更简洁,我尽可能地简化了所有内容。我更改了以前版本问题中的大部分信息,使其完全不同。这两个答案现在根本不相关,而不是曾经如此。赏金是自动奖励的。

如果这对某人有帮助,我可以将下载添加到我的实际项目中,但正如我所说,这个简化的示例与我的项目具有完全相同的形式。

【问题讨论】:

  • 您说您已在库和活动中为该属性设置了一个值,但我在您的问题中只看到一个 &lt;style&gt; 定义。那个确切的代码在两个地方都重复了吗?此外,您说您尝试从库中扩充布局;你到底是怎么做的?我猜测问题出在哪里,但我宁愿不要在不知道的情况下发布答案。

标签: android android-fragments android-styles android-library


【解决方案1】:

这个答案是基于我从你的问题和你和 Vinayak B 之间的对话中了解到的。如果我误解了,请纠正我。

place app 和 lib 中的 style.xml 有所不同。此外,我已经删除了 theme.xml 以及默认样式的 MyView.java 构造函数的更改

我改变了以下事情

  • 在主项目styles.xml中被覆盖

    <style name="AppTheme" parent="Theme.AppCompat.Light">
        <item name="myViewStyle">@style/MyViewStyleCustom</item>
    </style>
    
    <style name="MyViewStyleCustom" parent="MyViewStyle">
        <item name="labelStyle">@style/LabelStyle123</item>
    </style>
    
    <style name="LabelStyle123">
        <item name="android:textColor">#f00</item>
    </style>
    
  • 库样式.xml

    <resources>
        <style name="MyViewStyle">
            <item name="labelStyle">@style/LabelStyle</item>
            <item name="TextStyle">@style/textStyle</item>
        </style>
    
        <style name="LabelStyle">
            <item name="android:textColor">#00f</item>
        </style>
    
        <style name="textStyle">
            <item name="android:textColor">#009</item>
        </style>
    </resources>
    
  • MyView.java - 如果应用程序没有任何属性,则更改构造函数并设置默认 MyViewStyle。

    public MyView(Context context) {
        this(context, null, R.attr.myViewStyle,  R.style.MyViewStyle);
    }
    
    public MyView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, R.attr.myViewStyle,  R.style.MyViewStyle);
    }
    
    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, R.style.MyViewStyle);
    }
    
    public MyView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(createThemeWrapper(context, defStyleAttr,defStyleRes), attrs, defStyleAttr, defStyleRes);
        initLayout();
    }
    
    private static Context createThemeWrapper(Context context, int styleAttr, int defaultStyle) {
        final TypedArray ta = context.obtainStyledAttributes(new int[]{styleAttr});
        int style1 = ta.getResourceId(0, defaultStyle);
        ta.recycle();
        return new ContextThemeWrapper(context, style1);
    }
    

因此,如果它没有在主要活动样式中被覆盖或被覆盖的 labelStyle,它将采用默认 labelStyle

【讨论】:

  • 这与我已经在做的有什么不同?您将我的代码复制粘贴到答案中!
  • place app 和 lib 中的 style.xml 存在差异。此外,我已经删除了 theme.xml 以及默认样式的 MyView.java 构造函数的更改
  • 对不起,我说得太快了,非常感谢!问题可能与使用 0 作为默认样式属性的构造函数有关……我必须花费 10 个小时来解决这个问题,谢谢。如果您编辑答案,我可以更改否决票。
【解决方案2】:

此答案基于我对您的问题的理解。如果我误解了 ,请指正。

首先myTextColor 是库中的一个属性名称。不是属性值。当你使用这个库时,你应该为myTextColor 赋值。否则可能会出现'InflateException'。您可以通过以下方式避免这种情况。

<YourCustomeView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:myTextColor="#000"/>

1。库外使用时直接设置myTextColor值。

  1. 在您使用此myTextColor 属性的库中,检查此属性是否具有值。如果它没有任何值,则使用myTextColor的默认值

     private void init(@Nullable AttributeSet attrs) {
                 TypedArray ta = getContext().obtainStyledAttributes(attrs, 
                                 R.styleable.MyLibrary);
            boolean hasRawRes = ta.hasValue(R.styleable.myTextColor);
            if(hasRawRes){
              // Use `myTextColor` attr here
            }else{
              // use default color
            }
    

    }

更新答案

更新问题的答案

首先,您尝试使用 ?attr/ 从库中获取 attr 值到您的项目中。这不起作用。因为

您的项目使用Theme.AppCompat 主题作为(我猜)您的活动的父主题。当您在该活动中使用?attr 时,您只能获取Theme.AppCompat 的属性值。但是您正在尝试获取?attr/labelStyle,这不是Theme.AppCompat 的属性,而不是您的库属性。这就是为什么你会崩溃。如果您想将库中的任何样式用于您的项目,您可以使用@style 标签

例如

 style="@style/labelStyle"

如果不是你要找的,请分享你的源代码。这样我可以更了解这个问题。

【讨论】:

  • 不,我想创建一个颜色属性,就像?attr/colorPrimary 一样。 This article 解释了我正在尝试做的事情,但它似乎在图书馆中不起作用
  • 在这种情况下,第二个选项会帮助你。请尝试一下。无论如何,如果您想在项目中使用 '?attr/myTextColor',则必须在项目的 style.xml 中设置一个值。
  • @VinayakB 似乎是写的,它也是你引用的 SublimePicker 库的工作方式。我认为您误解了自定义样式属性定义的目的,它不是用于全局库,而是用于 customView 定义。在你的情况下,你只需要在你的库中定义一个默认的文本颜色资源,并在你的应用程序中覆盖它,它应该可以完成工作。
  • 是的,我正在将我的对话框片段更改为自定义视图,而不是像在 Sublime 选择器中一样,它可能对我有帮助。
  • @VinayakB 我有点晚了,但我刚刚测试了第二个选项,它没有价值......
【解决方案3】:

这是我的猜测:我怀疑,尽管您在上面发布了 &lt;style&gt; 标签,但在从您的库中进行膨胀时,该属性实际上并未定义,可能是因为您的库项目使用带有“坏”主题的 Context膨胀对话框。

?attr 语法意味着变量的值是从上下文的主题 中读取的,而不是从视图的样式或属性中读取的。来自 Google 开发者博客文章:

这种 ?attr/ 格式允许您从主题中提取任何属性,从而可以轻松地将主题整合到一个地方,避免在多个文件中查找/替换。

因此,您必须确保处理膨胀上下文的主题未定义此属性的情况,或者仅使用定义该属性的主题来膨胀此对话框。

【讨论】:

    猜你喜欢
    • 2017-02-15
    • 2011-06-02
    • 1970-01-01
    • 1970-01-01
    • 2013-04-03
    • 2013-10-03
    • 2016-08-19
    • 1970-01-01
    • 2014-02-22
    相关资源
    最近更新 更多