I have this attribute declared on attrs.xml:
<resources>
<attr name="customColorPrimary" format="color" value="#076B07"/>
</resources>
I need to get it's value, which should be "#076B07", but instead I'm getting an integer: "2130771968"
I'm accessing the value this way:
int color = R.attr.customColorFontContent;
Is there a correct way to get the real value of this attribute?
Thank you
No, this is not the correct way, as the integer R.attr.customColorFontContent is a resource identifier generated by Android Studio when your app is compiled.
Instead, you'll need to get the color that is associated with the attribute from the theme. Use the following class to do this:
public class ThemeUtils {
private static final int[] TEMP_ARRAY = new int[1];
public static int getThemeAttrColor(Context context, int attr) {
TEMP_ARRAY[0] = attr;
TypedArray a = context.obtainStyledAttributes(null, TEMP_ARRAY);
try {
return a.getColor(0, 0);
} finally {
a.recycle();
}
}
}
You can then use it like this:
ThemeUtils.getThemeAttrColor(context, R.attr.customColorFontContent);
You should access color attribute as follows:
public MyCustomView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyCustomView, 0, 0);
try {
color = ta.getColor(R.styleable.MyCustomView_customColorPrimary, android.R.color.white); //WHITE IS THE DEFAULT COLOR
} finally {
ta.recycle();
}
...
}
Related
attrs.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="InteractiveImageView">
<attr name="play_anim" format="reference|integer" />
</declare-styleable>
</resources>
usage_example(activity_main).xml
<com.doitandroid.mylottie.InteractiveImageView
app:play_anim="#raw/icon_home">
</com.doitandroid.mylottie.InteractiveImageView>
When I want to add this view programmatically, How to do this?
MainActivity.java:
LinearLayout linearLayout = findViewById(R.id.main_ll);
InteractiveImageView interactiveImageView = new InteractiveImageView(this);
linearLayout.addView(interactiveImageView);
I don't know how to add app:play_anim="#raw/icon_home" this part.
You should have a constructor in the form of:
public InteractiveImageView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
loadAttributes(attrs); //Here use the attributes.
}
Use AttributeSet to pass your values.
Example:
private void loadAttributes(AttributeSet attrs) {
if (attrs != null) {
TypedArray typedArray = mContext.obtainStyledAttributes(attrs, R.styleable.AudioPlayerView);
mBackgroundDrawable = typedArray.getDrawable(R.styleable.AudioPlayerView_player_background);
}
}
You should have a function on your custom view like
public void setPlayAnim(#RawRes int playAnim) {
// do something
}
then you can call from code like
interactiveImageView.setPlayAnim(R.raw.somthing)
I have a custom progress bar used around the app which has a attribute for setting the indeterminate color. Since I am using the support library I am trying to have the progress bar colored on older android versions too.
In attrs I have something like:
<declare-styleable name="TestView">
<attr name="testColor" format="color"/>
</declare-styleable>
When declaring the view:
<com.TestView
....
app:testColor="#color"
/>
Then my custom view is like this:
public class TestView extends ProgressBar {
public TestView(Context context) {
super(context);
applyTint(Color.WHITE);
}
public TestView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray attributes = context.getTheme().obtainStyledAttributes(attrs, R.styleable.TestView, 0, 0);
try {
applyTint(attributes.getColor(R.styleable.TestView_testColor, Color.WHITE));
} finally {
attributes.recycle();
}
}
public TestView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, android.support.design.R.style.Base_Widget_AppCompat_ProgressBar);
TypedArray attributes = context.getTheme().obtainStyledAttributes(attrs, R.styleable.TestView, 0, 0);
try {
applyTint(attributes.getColor(R.styleable.TestView_testColor, Color.WHITE));
} finally {
attributes.recycle();
}
}
private void applyTint(int color) {
if (Build.VERSION.SDK_INT >= 21) {
setIndeterminateTintList(ColorStateList.valueOf(color));
} else {
getIndeterminateDrawable().setColorFilter(color, PorterDuff.Mode.SRC_IN);
}
}
}
The problem I have is that it seems that the attribute of color is somehow shared between instances of TestView.
How can I have each view to keep its own attribute value?
Later edit: seems to work fine on android 6 but fails on 4.4.2
Got the answer at https://stackoverflow.com/a/37434219/379865
Basically I had to update my tint apply code with:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
DrawableCompat.setTint(DrawableCompat.wrap(getIndeterminateDrawable()), color);
else {
DrawableCompat.wrap(getIndeterminateDrawable()).mutate().setColorFilter(color, PorterDuff.Mode.SRC_IN);
}
I´m trying to outsource my custom view into an own library.
Is it possible to get the colorPrimary, colorPrimaryDark and colorAccent attributes outside the scope, maybe at runtime?
Solution
I´ve pointed it out myself.
In xml use:
?attr/attributeName
f.e.
?attr/colorAccent
In code use sth like:
public int getColorValueByAttr(Context context, int attrResId) {
int color = 0;
TypedArray a = null;
try {
int[] attrs = {attrResId};
a = context.obtainStyledAttributes(attrs);
color = a.getColor(0, 0);
} finally {
if (a != null) {
a.recycle();
}
}
return color;
}
I have a custom view A that has a TextView. I Made a method that returns the resourceID for the TextView. If no text is defined the method will return -1 by default.
I also have a custom view B that inherits from view A. My custom view has the text 'hello'. When I call the method to get the attribute of the super class I get -1 back instead.
In the code there is also an example of how i'm able to retrieve the value but it feels kind of hacky.
attrs.xml
<declare-styleable name="A">
<attr name="mainText" format="reference" />
</declare-styleable>
<declare-styleable name="B" parent="A">
<attr name="subText" format="reference" />
</declare-styleable>
Class A
protected static final int UNDEFINED = -1;
protected void init(Context context, AttributeSet attrs, int defStyle)
{
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.A, defStyle, 0);
int mainTextId = getMainTextId(a);
a.recycle();
if (mainTextId != UNDEFINED)
{
setMainText(mainTextId);
}
}
protected int getMainTextId(TypedArray a)
{
return a.getResourceId(R.styleable.A_mainText, UNDEFINED);
}
Class B
protected void init(Context context, AttributeSet attrs, int defStyle)
{
super.init(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.B, defStyle, 0);
int mainTextId = getMainTextId(a); // this returns -1 (UNDEFINED)
//this will return the value but feels kind of hacky
//TypedArray b = context.obtainStyledAttributes(attrs, R.styleable.A, defStyle, 0);
//int mainTextId = getMainTextId(b);
int subTextId = getSubTextId(a);
a.recycle();
if (subTextId != UNDEFINED)
{
setSubText(subTextId);
}
}
Another solution I have found so far is to do the following. I also think this is kind of hacky.
<attr name="mainText" format="reference" />
<declare-styleable name="A">
<attr name="mainText" />
</declare-styleable>
<declare-styleable name="B" parent="A">
<attr name="mainText" />
<attr name="subText" format="reference" />
</declare-styleable>
How to get an attribute from a super class of a custom view?
I can't seem to find any good examples on how inheritance works with custom views.
Apparently this is the right way to do it:
protected void init(Context context, AttributeSet attrs, int defStyle) {
super.init(context, attrs, defStyle);
TypedArray b = context.obtainStyledAttributes(attrs, R.styleable.B, defStyle, 0);
int subTextId = getSubTextId(b);
b.recycle();
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.A, defStyle, 0);
int mainTextId = getMainTextId(a);
a.recycle();
if (subTextId != UNDEFINED) {
setSubText(subTextId);
}
}
There is an example at the source of TextView.java. at line 1098
In a custom view group, I have a TextView as a child. I want to set this TextView's textColor based on android:textColor value. So in res/values/styles.xml I have:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CustomViewGroupTextView">
<attr name="android:textColor" />
</declare-styleable>
</resources>
And in CustomViewGroup's constructor, I have this:
private TextView mTextView;
public CustomViewGroup(Context context) {
super(context);
initTextView(context, attrs);
}
public CustomViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
initTextView(context, attrs);
}
public CustomViewGroup(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initTextView(context, attrs);
}
private void initTextView(Context context, AttributeSet attrs) {
mTextView = new TextView(
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CustomViewGroupTextView);
// Set text color
ColorStateList textColor = ta.getColorStateList(R.styleable.MinutiaeTextView_android_textColor);
if (textColor != null) {
mTextView.setTextColor(textColor);
}
}
My question is: how do I properly do mTextView.setTextColor? Anyone can put a whole color state list or a single color value in android:textColor. Or will I get a ColorStateList with all the same color if someone put a single color in android:textColor?
According to the documentation:
The value may be either a single solid color or a reference to a color or complex ColorStateList description
So, if the user set the color to a single value, you will get a single value, else you will get a reference to a ColorStateList.
There are some ways to change the color of a TextView:
mTextView.setTextColor(Color.RED); (RED, WHITE, BLACK....)
mTextView.setTextColor(Color.rgb(200,0,0));
mTextView.setTextColor(getResources().getColor(R.color.yourcolor));
mTextView.setTextColor(0xAARRGGBB);
EDIT:
In your layout xml file use this property in the specific TextView:
android:textColor="Here"
Where you read Here you can write:
android:color/white (black, red...)
color/yourcolorname
#738184
Etc...