即使明确设置了库的样式属性也没有值

问题描述 投票:7回答:3

我创建了一个带有自定义视图的库,可以在创建时扩展布局。布局中的视图使用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)
      [...]

布局inflater无法找到属性的值。当我试图通过代码获取属性时,它什么都不返回。该属性实际存在,只有它没有设置值,即使我已经明确设置了一个。

我应该如何设计我的图书馆风格?我几乎可以肯定我做的每一件事都和SublimePicker library一样,但它不会起作用。使用ContextThemeWrapper的部分有一点不同,但它可能不是问题。我觉得我忘记了一个小东西,使得属性没有价值,有些东西没有连接,我不知道。

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

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

android android-fragments android-styles android-library
3个回答
5
投票

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

在app 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>
  • lib styles.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


4
投票

这个答案是基于我从你的问题中理解的。如果我曲解,请纠正我。

首先,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"

如果它不是您想要的,请分享您的源代码。所以我可以更多地了解这个问题。


0
投票

这是我的猜测:我怀疑,尽管你在上面发布了<style>标签,但实际上没有定义属性从库中膨胀时,可能是因为你的库项目在膨胀对话框时使用了带有“坏”主题的Context

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

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

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

© www.soinside.com 2019 - 2024. All rights reserved.