Working with styleable - android

I wanted to make a view containing a progress view and a button. Through the view's xml I wanted to add fields that define button and porgress bar style.
What I've done so far but it does not work:
<io.**.**.view.ButtonLoading android:id="#+id/b_recover_password"
android:layout_width="wrap_content"
android:gravity="center"
app:styleButton="#style/ButtonGrey"
app:styleProgress="#style/ProgressBar"
app:textButton="#string/recover_password"
android:layout_height="wrap_content"/>
Code:
a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.ButtonLoading,
0, 0);
int buttonId = 0;// R.style.Widget_AppCompat_Button;
try {
buttonId = a.getResourceId(R.styleable.ButtonLoading_styleButton, 0);
} catch (Exception e) {
}
button = new Button(getContext(), attrs, buttonId);
LayoutParams lpButton = createLayoutParams();
button.setLayoutParams(lpButton);
color = button.getCurrentTextColor();
int progressId = 0;// R.style.Widget_AppCompat_ProgressBar;
try {
progressId = a.getResourceId(R.styleable.ButtonLoading_styleProgress, 0);
} catch (Exception e) {
}
progressBar = new ProgressBar(getContext(), attrs, progressId);
LayoutParams lpProgressBar = createLayoutParams();
lpProgressBar.addRule(RelativeLayout.CENTER_IN_PARENT);
progressBar.setLayoutParams(lpProgressBar);
LayoutParams lpRelativeLayout = createLayoutParams();
setLayoutParams(lpRelativeLayout);
addView(button);
addView(progressBar);
try {
String value = a.getString(R.styleable.ButtonLoading_textButton);
button.setText(value);
} catch (Exception e) {
}
a.recycle();
Styleable:
<declare-styleable name="ButtonLoading">
<attr name="styleButton" format="reference" />
<attr name="styleProgress" format="reference" />
<attr name="textButton" format="string" />
</declare-styleable>
Someone help me? thanks

The problem is in your constructors for Button and ProgressBar. Let's consider two of the constructors. (Emphasis is mine.) (Documentation)
View(Context context, AttributeSet attrs, int defStyleAttr) [Appropriate for below API 21]
Perform inflation from XML and apply a class-specific base style from a theme attribute. This constructor of View allows subclasses to use their own base style when they are inflating. For example, a Button class's constructor would call this version of the super class constructor and supply R.attr.buttonStyle for defStyleAttr; this allows the theme's button style to modify all of the base view attributes (in particular its background) as well as the Button class's attributes.
View(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) [Appropriate for API 21+]
Perform inflation from XML and apply a class-specific base style from a theme attribute or style resource. This constructor of View allows subclasses to use their own base style when they are inflating.
Focusing on the last two arguments.
defStyleAttr int: An attribute in the current theme that contains a reference to a style resource that supplies default values for the view. Can be 0 to not look for defaults.
defStyleRes int: A resource identifier of a style resource that supplies default values for the view, used only if defStyleAttr is 0 or can not be found in the theme. Can be 0 to not look for defaults.
It is confusing because there are resource ids pointing to resource ids, but bear with me.
What you have defined for buttonId and progressId is a resource id that points to a style (<style...). This style resource id is appropriate to use for the defStyleRes attribute of the Button and ProgressBar constructors as noted .above. You are trying to use each of these resource values as an id that points to an attribute in the current theme. In other words, you are saying that R.attr.styleButton (styleButton) is an attribute in the current theme which it is not as currently defined. To fix this, change the theme style to the following:
styles.xml
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="styleButton">#style/ButtonGrey</item>
...
</style>
To make what you have work with API 21+ you can leave the leave the style and layout files as they are and change the custom view code to something like the following. (I am only showing code for the button, but the progress bar would be similar.) You may want to create a separate style file for API 21+ (styles-v21.xml).
public CustomViewGroup(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.ButtonLoading,
0, 0);
int defStyleRes = 0;
try {
defStyleRes = a.getResourceId(R.styleable.ButtonLoading_styleButton, 0);
} catch (Exception e) {
// do something
}
Button button;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// defStyleRes is only used if defStyleAttr == 0
// or can't be found in the current theme.
button = new Button(getContext(), attrs, defStyleAttr, defStyleRes);
} else {
button = new Button(getContext(), attrs,
(defStyleAttr != 0) ? defStyleAttr : R.attr.styleButton);
}
try {
String value = a.getString(R.styleable.ButtonLoading_textButton);
button.setText(value);
} catch (Exception e) {
// do something
}
addView(button);
a.recycle();
}
Setting the text of the button proceeds as you have coded. Styles are trickier. To makeapp:styleButton="#style/ButtonGrey" work as you intended for all APIs, I think that you would have to do something like this.
I hope this helps.

The my styles is:
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorAccent</item>
<item name="android:buttonStyle">#style/ButtonAppTheme</item>
<item name="android:progressBarStyle">#style/ProgressBarBase</item>
</style>
<style name="ProgressBarBase" parent="android:Widget.Holo.Light.ProgressBar">
<item name="android:textColorTertiary">#color/color_grey</item>
</style>
<style name="ProgressBar" parent="android:Widget.Holo.Light.ProgressBar">
<item name="android:textColorTertiary">#color/color_black</item>
</style>
The problem is that you always have the "ProgressBarBase" style. That is, it is not overriding.

Related

Library's style attributes have no values even though they are explicitly set

I made a library with a custom view that inflates a layout when created. Views in the layout are styled with style="?attr/labelStyle" or any other attribute.
The attribute is declared the library's attrs.xml:
<attr name="myViewStyle" format="reference"/>
<declare-styleable name="MyView">
<attr name="labelStyle" format="reference|color"/>
</declare-styleable>
I have set a default value to this attribute in the library's 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>
And finally in the library's themes.xml:
<style name="MyViewStyleLight" parent="Theme.AppCompat.Light">
<item name="myViewStyle">#style/MyViewStyle</item>
</style>
Now this was the library's default styles, but it is overridden in the main project 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>
The 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 explain about the ContextThemeWrapper below. Now the app crashes on the line where the layout gets inflated. Here's the 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)
[...]
The layout inflater can't find the attribute's value. When I tried to get the attribute by code, it returns nothing. The attribute actually exists, only it has no value set to it even though I have clearly set one.
How exactly I am supposed to style my library? I am almost certain that I did every thing the same as the SublimePicker library but it just won't work. There's a little difference in the part with the ContextThemeWrapper, but it probably isn't the problem. I feel like I forgot a tiny thing somewhere that makes the attribute have no value, 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. The two answers are not relevant at all now, not that they ever were. The bounty was automatically rewarded.
If that could help someone I can add a download to my actual project, but as I said this simplified example has the exact same form as my project.
This answer is based on what I understand from your question and conversation between you and Vinayak B. If I misinterpret ,Please correct me.
there is difference in style.xml in both place app as well as lib. addition I have removed theme.xml as well as changes in constructor of MyView.java for default style
I have changed following things
overridden in the main project 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 - changed constructor of and set default MyViewStyle if no any attribute come from 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 take default labelStyle if it is not overridden in main activity style or overridden labelStyle
This answer is based on what I understand from your question. If I misinterpret
,Please correct me.
First of all myTextColor is an attribute name in your library. not a attribute value. You supposed to give a value for myTextColor when ever you using this library. Otherwise there may occur 'InflateException' . You can avoid this by following way.
<YourCustomeView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:myTextColor="#000"/>
1. Set myTextColor value directly when you use outside the library.
OR
In your library where you using this myTextColor attribute, check if this attribute have value or not. If it doesn't have any value then use a 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 for the updated question
First of all you are trying to fetch a attr value from your library to your project using ?attr/ .Which does not going to work. because
Your project using Theme.AppCompat theme as (I'm guessing) parent theme for your Activities. When you use ?attr inside that activity, you can only fetch attribute values of Theme.AppCompat. But you are trying to fetch ?attr/labelStyle which is not a attribute of Theme.AppCompat rather than it's your library attribute. That's why you are getting that crash. If you want to use any style from your library to your project you can use #style tag
For example
style="#style/labelStyle"
If it's not what you are looking for ,Please kindly share your source code.So I can understand more on this problem.
Here's my guess: I suspect that, despite <style> tag you posted above, the attribute is actually not defined when inflating from your library, probably because your library project is using a Context with a "bad" theme when inflating the dialog.
The ?attr syntax means that the value for the variable is read from the context's theme, not from a view's style or attributes. From a Google dev blog post:
This ?attr/ format allows you to pull any attribute out of your theme, making it easy to consolidate your theming into a single place and avoid finding/replacing across many files.
So you have to make sure that you either handle the case where the inflating context's theme does not define this attribute, or only ever inflate this dialog with a theme that defines the attribute.

Get Android default Tab indicator color

I was trying to make a tricky layout for which i need the Android's default tab indicator color.
I have searched a lot but every where I find how to change and customize tab indicator but could not find how to get color code in hex of default tab indicator.
I did some research for your question, I hope this will help you.
The tab indicator color is set in the Inner Class SlidingTabStrip of the class TabLayout (Code). Sadly you can't access this variable.
private class SlidingTabStrip extends LinearLayout {
private final Paint mSelectedIndicatorPaint;
// ...
void setSelectedIndicatorColor(int color) {
if (mSelectedIndicatorPaint.getColor() != color) {
mSelectedIndicatorPaint.setColor(color);
ViewCompat.postInvalidateOnAnimation(this);
}
}
}
But in a constructor of the TabLayout the default tab indicator color is set.
public TabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// Add the TabStrip
mTabStrip = new SlidingTabStrip(context);
addView(mTabStrip, LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TabLayout, defStyleAttr, R.style.Widget_Design_TabLayout);
// <-- HERE
mTabStrip.setSelectedIndicatorColor(a.getColor(R.styleable.TabLayout_tabIndicatorColor, 0));
}
I think you need to access R.styleable.TabLayout_tabIndicatorColor to get what you want. I don't have the possibility right now to test if and how it works but I hope this helps you a bit.
Update
I tried this at home and it seems to work. I used this code in the onCreate() method of my Activity
TypedArray a = getContext().obtainStyledAttributes(null, R.styleable.TabLayout, 0, R.style.Widget_Design_TabLayout);
// returns -16738680 in my case which is the accentColor
int color = a.getColor(R.styleable.TabLayout_tabIndicatorColor, 0);
But I saw, that R.styleable.TabLayout_tabIndicatorColor just links to the accentColor. Maybe this is the better way to get what you want.
<style name="Base.Widget.Design.TabLayout" parent="android:Widget">
<item name="tabIndicatorColor">?attr/colorAccent</item>
<!-- other items -->
</style>

Themeing the Popup of the ShareActionProvider from ActionBarSherlock

I want to theme the ShareActionProvider of the ActionBarSherlock. My problem is that I successfully customized the styles of the ActionBar but I cannot style the share popup which comes from the ActionBarSherlock.
In the Screenshot above you can see the share popup uses the default styles while a normal more popup is styled in that way I like.
I digged more thrue the source code and found in ActivityChooserView this method:
private IcsListPopupWindow getListPopupWindow() {
if (mListPopupWindow == null) {
mListPopupWindow = new IcsListPopupWindow(getContext());
//...
Which is as far I know responsable for creating that Popup of the ShareActionProvider. As you can see above a new instance of IcsListPopupWindow is created. Here are the constructors of IcsListPopupWindow:
public IcsListPopupWindow(Context context) {
this(context, null, R.attr.listPopupWindowStyle);
}
public IcsListPopupWindow(Context context, AttributeSet attrs, int defStyleAttr) {
mContext = context;
mPopup = new PopupWindow(context, attrs, defStyleAttr);
mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
}
So far the attr com.actionbarsherlock.R.attr.listPopupWindowStyle used. While this attr is inserted the one and two parameter constructor of IcsListPopupWindow created a new PopupWindow with the attr com.android.internal.R.attr.popupWindowStyle which seems to be equal with android.R.attr.popupWindowStyle:
public PopupWindow(Context context, AttributeSet attrs) {
this(context, attrs, com.android.internal.R.attr.popupWindowStyle);
}
public PopupWindow(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
mContext = context;
mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
TypedArray a =
context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.PopupWindow, defStyleAttr, defStyleRes);
mBackground = a.getDrawable(R.styleable.PopupWindow_popupBackground);
// ...
There you can see that the background image is loaded from a style called styleable.PopupWindow_popupBackground. I tried to apply my style with this xml file:
<style name="Theme.MyStyle" parent="#style/Theme.Sherlock.Light.DarkActionBar">
<!-- ... -->
<item name="actionDropDownStyle">#style/DropDownNav.MyStyle</item>
<item name="dropDownListViewStyle">#style/DropDownListView.MyStyle</item>
<item name="actionBarItemBackground">#drawable/selectable_background_mystyle</item>
<item name="listPopupWindowStyle">#style/DropDownNav.MyStyle</item>
<item name="android:listPopupWindowStyle">#style/DropDownNav.MyStyle</item>
</style>
<style name="DropDownNav.MyStyle" parent="#style/Widget.Sherlock.Spinner.DropDown.ActionBar">
<item name="android:popupBackground">#drawable/menu_dropdown_panel_mystyle</item>
<item name="android:divider">#081925</item>
<item name="android:dividerHeight">1dp</item>
</style>
<style name="DropDownListView.MyStyle" parent="#style/Widget.Sherlock.ListView.DropDown">
<item name="android:divider">#081925</item>
<item name="android:dividerHeight">1dp</item>
</style>
But it does not work. What am I doing wrong?
By the way I would be really happy if someone could give me a good tutorial for styleable and the attr stuff I don't get it right.
I was able to override the popupBackground color by overriding this ABS style:
<style name="Widget.Sherlock.Light.ListPopupWindow" parent="Widget">
<item name="android:popupBackground">#333333</item>
</style>
Hopefully that can get you going. And if you were able to solve it on your own, please share with the rest of us how you styled the rest of the attributes.
Cheers

Changing Font for an enitre Android App?

Is there any way to change the font for an entire Android application ? I'm aware of changing the font for each TextView and Buttons. I just wanted to know if there's a more elegant way of doing it since the program i'm working on has tons of layout files :(
to Apply same font effect through out the app you need to create your own custom TextView and Button class which has applied your custom font. and the use them in your layouts as normal views.
public class MinnesotaTextView extends TextView{
public MinnesotaTextView(Context context) {
super(context);
if(!isInEditMode()){
textViewProprties(context);
}
}
public MinnesotaTextView(Context context, AttributeSet attrs){
super(context, attrs);
if(!isInEditMode()){
textViewProprties(context);
}
}
public MinnesotaTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if(!isInEditMode()){
textViewProprties(context);
}
}
private void textViewProprties(Context context){
Typeface tfs = Typeface.createFromAsset(context.getAssets(), "Helvetica.ttf");
setTypeface(tfs);
setMaxLines(4);
}
}
here's Button:
public class MinnesotaButton extends Button {
public MinnesotaButton(Context context){
super(context);
if(!isInEditMode()){
buttonProprties(context);
}
}
public MinnesotaButton(Context context, AttributeSet attrs){
super(context, attrs);
if(!isInEditMode()){
buttonProprties(context);
}
}
public MinnesotaButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if(!isInEditMode()){
buttonProprties(context);
}
}
private void buttonProprties(Context context){
setPadding(0, 4, 0, 0);
setBackgroundResource(R.drawable.bg_red_btn);
setGravity(Gravity.CENTER_HORIZONTAL|Gravity.CENTER_VERTICAL);
setTextSize(13.0f);
setTextColor(context.getResources().getColor(R.color.white));
Typeface tfs = Typeface.createFromAsset(context.getAssets(), "garreg.ttf");
setTypeface(tfs,1);
}
}
There are two ways you can do this, depending on how much control you need:
1) You can create a custom style attribute in styles.xml, something like:
<style name="CodeFont" parent="#android:style/TextAppearance.Medium">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textColor">#00FF00</item>
<item name="android:typeface">monospace</item>
</style>
Keep in mind that this is a pretty limited approach, style may not contain everything you need.
2) You can create subclasses of TextView and Button and put your styling code in their constructors. I'd recommend this way because you can use whatever custom assets you might need. (I just saw that Nasser beat me to a code sample for this, check it out - it looks right)
You can play with several attributes related to your theme to modify the default font colors on your application.
Here is an example for the theme Holo Light, you have to first change your manifest file to call your custom theme, and then customize your custom theme in the file styles.xml.
Here is the part of the manifest file you need to change to call your custom theme (the custom theme called here is AppTheme:
<application
android:name="YourApplication"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
Then in your file styles.xml, create and customize this custom theme:
<style name="AppTheme" parent="#android:style/Theme.Holo.Light">
<item name="android:textColorPrimary">#color/red</item>
<item name="android:textColorSecondary">#color/blue</item>
<item name="android:textColorTertiary">#color/yellow</item>
</style>
These 3 parameters textColorPrimary, textColorSecondary and textColorTertiary will impact elements/components all over your application.

How do I use obtainStyledAttributes(int []) with internal Themes of Android

So I have looked around and found out that android.R.styleable is no longer part of the SDK even though it is still documented here.
That wouldn't really be an issue if it was clearly documented what the alternative is. For example the AOSP Calendar App is still using the android.R.styleable
// Get the dim amount from the theme
TypedArray a = obtainStyledAttributes(com.android.internal.R.styleable.Theme);
lp.dimAmount = a.getFloat(android.R.styleable.Theme_backgroundDimAmount, 0.5f);
a.recycle();
So how would one get the backgroundDimAmount without getting the int[] from android.R.styleable.Theme?
What do I have to stick into obtainStyledAttributes(int []) in order to make it work with the SDK?
The CustomView API demo shows how to retrieve styled attributes. The code for the view is here:
https://github.com/android/platform_development/blob/master/samples/ApiDemos/src/com/example/android/apis/view/LabelView.java
The styleable array used to retrieve the text, color, and size is defined in the <declare-styleable> section here:
https://github.com/android/platform_development/blob/master/samples/ApiDemos/res/values/attrs.xml#L24
You can use <declare-styleable> to define any list of attributes that you want to retrieve as a group, containing both your own and ones defined by the platform.
As far as these things being in the documentation, there is a lot of java doc around the styleable arrays that makes them useful to have in the documentation, so they have been left there. However as the arrays change, such as new attributes being added, the values of the constants can change, so the platform ones can not be in the SDK (and please do not use any tricks to try to access them). There should be no need to use the platform ones anyway, because they are each there just for the implementation of parts of the framework, and it is trivial to create your own as shown here.
In the example, they left out the reference to the Context 'c':
public ImageAdapter(Context c) {
TypedArray a = c.obtainStyledAttributes(R.styleable.GalleryPrototype);
mGalleryItemBackground = a.getResourceId(
R.styleable.GalleryPrototype_android_galleryItemBackground, 0);
a.recycle();
return mGalleryItemBackground;
}
Changing obtainStyledAttributes to c.obtainStyledAttributes should work
Example of pulling out standard attribute (background) in a custom view which has its own default style. In this example the custom view PasswordGrid extends GridLayout. I specified a style for PasswordGrid which sets a background image using the standard android attribute android:background.
public class PasswordGrid extends GridLayout {
public PasswordGrid(Context context) {
super(context);
init(context, null, 0);
}
public PasswordGrid(Context context, AttributeSet attrs) {
super(context, attrs, R.attr.passwordGridStyle);
init(context, attrs, 0);
}
public PasswordGrid(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs, defStyle);
}
private void init(Context context, AttributeSet attrs, int defStyle) {
if (!isInEditMode()) {
TypedArray stdAttrs = context.obtainStyledAttributes(attrs,
new int[] { android.R.attr.background }, // attribute[s] to access
defStyle,
R.style.PasswordGridStyle); // Style to access
// or use any style available in the android.R.style file, such as
// android.R.style.Theme_Holo_Light
if (stdAttrs != null) {
Drawable bgDrawable = stdAttrs.getDrawable(0);
if (bgDrawable != null)
this.setBackground(bgDrawable);
stdAttrs.recycle();
}
}
}
Here is part of my styles.xml file:
<declare-styleable name="passwordGrid">
<attr name="drawOn" format="color|reference" />
<attr name="drawOff" format="color|reference" />
<attr name="pathWidth" format="integer" />
<attr name="pathAlpha" format="integer" />
<attr name="pathColor" format="color" />
</declare-styleable>
<style name="PasswordGridStyle" parent="#android:style/Widget.GridView" >
<!-- Style custom attributes. -->
<item name="drawOff">#drawable/ic_more</item>
<item name="drawOn">#drawable/ic_menu_cut</item>
<item name="pathWidth">31</item>
<item name="pathAlpha">129</item>
<item name="pathColor">#color/green</item>
<!-- Style standard attributes -->
<item name="android:background">#drawable/pattern_bg</item>
</style>
This appears to be a bug in the SDK. I have filed an issue on it, which you may wish to star so as to receive updates on it.
As a worksaround, you can use reflection to access the field:
Class clazz=Class.forName("android.R$styleable");
int i=clazz.getField("Theme_backgroundDimAmount").getInt(clazz);

Categories

Resources