Library style attributes have no meaning, even if they are explicitly set

Current answers do not help, this question does not answer

I created a library with a custom view that inflates the layout upon creation. Views in the layout are styled using style="?attr/labelStyle" or any other attribute.

The attribute is declared by the attrs.xml library:

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

I set the default value for this attribute in the styles.xml library:

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

And finally, in the themes.xml library:

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

Now these were the default library styles, but they were overridden in the main styles.xml project

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

Custom view code:

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

I will talk about ContextThemeWrapper below. Now the application crashes on the line where the layout swells. Here is an important part of the crash log:

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

Layout expansion cannot find attribute value. When I tried to get the attribute by code, it returns nothing. The attribute really exists, only it does not have the value set for it, although I clearly set it.

How exactly should I create my library? I'm pretty sure that I did the same as the SublimePicker library , but that just won't work. There's a slight difference in part with ContextThemeWrapper, but that is probably not a problem. I feel like I forgot a tiny thing somewhere that makes the attribute inappropriate, something is not connected, I don’t know.

I know this is a very long question, but it cannot be more concise, I simplified everything as much as I could. I changed most of the information that was in the previous version of my question, making it completely different. These two answers are not relevant right now, not what they have ever been. The reward was automatically rewarded.

If this can help someone, I can add the download to my actual project, but as I said, this simplified example has the same form as my project.

+5
source share
3 answers

This answer is based on what I understand from your question and the conversation between you and Vinayak B. If I misinterpreted, please correct me.

there is a difference in style.xml in both the application and the lib. In addition, I removed theme.xml, as well as changes to the MyView.java constructor for the default style

I changed the following things

  • overridden in the main styles.xml project

     <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 - changed the constructor and set MyViewStyle by default if no attribute came from the application.

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

so either it will accept the default labelStyle if it is not overridden in the main activity style or overridden labelStyle

+3
source

This answer is based on what I understand from your question. If I misinterpret, Please correct me.

First of all, myTextColor is the name of the attribute in your library. not the attribute value. You must give the value myTextColor when you use this library. Otherwise, an 'InflateException' may occur. You can avoid this as follows.

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

1. Set the value myTextColor directly when used outside the library.

OR

  1. In your library where you use this myTextColor attribute, check if this attribute has a value or not. If it doesn't matter, use the default value for 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 } 

    }

UPDATE ANSWER

This answer is for an updated question.

First of all, you are trying to extract the attr value from your library into your project using ?attr/ . This will not work. because

Your project uses the Theme.AppCompat theme as (I assume) the parent theme for your activity. When you use ?attr inside this action, you can only get the Theme.AppCompat attribute Theme.AppCompat . But you are trying to get ?attr/labelStyle , which is not an attribute of Theme.AppCompat , not an attribute of your library. That is why you get this crash. If you want to use any style from your library for your project, you can use the @style tag

for instance

  style="@style/labelStyle" 

If this is not what you are looking for, please share your source code. Therefore, I can better understand this problem.

+4
source

Here I am assuming: I suspect that despite the <style> tag you mentioned above, the attribute is not really defined when inflating from your library, possibly because your library project uses Context with a "bad" theme when inflating dialogue.

The syntax ?attr means that the value of the variable is read from the context topic, and not from the style or attributes of the view. From the Google dev blog post:

This attr / format attribute allows you to pull any attribute from your theme, making it easy to combine topics in one place and avoiding searching / replacing in many files.

So you have to make sure that you are either handling the case where the theme of context bloating does not define this attribute, or only ever bloating this dialog box with a theme that defines the attribute.

0
source

Source: https://habr.com/ru/post/1273655/


All Articles