Get standard layout attributes - android

I extended the class ImageView and added some custom parameters. I succeed to get these custom parameters from my code, using the method Context.getTheme().obtainStyledAttributes().
What I need is to access the standard parameters of the ImageView object, such as android:src and android:background. I know it exist the class android.R.styleable.* which I could use to get those parameters, but that class has been deprecated (and is not visible anymore). What can I do to access those android parameters?

While I’m not sure how to extract parent values from a TypedArray, you’re able to access them with appropriate getters, e.g.:
public class MyImageView extends ImageView {
public MyImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
final TypedArray array = getContext().obtainStyledAttributes(attrs, R.styleable.whatever);
try {
// get custom attributes here
} finally {
array.recycle();
}
// parent attributes
final Drawable background = getBackground();
final Drawable src = getDrawable();
// etc.
}
}
It's not exactly what you're looking for, but it might help.

Related

Is there a way to set MotionLayout custom attribute for MaterialButton's iconTint?

According to this article
CustomAttribute are specified with the attributeName, which needs to match the getter/setter methods of an object such that:
getter: getName (e.g. getBackgroundColor)
setter: setName (e.g. setBackgroundColor)
(so motion:attributeName need to be backgroundColor)
I've tried bellow attribute names with material button, but none of them worked.
<CustomAttribute motion:attributeName="IconTintResource" motion:customColorValue="#color/keyTextColor" />
'IconTintResource', 'iconTintResource', 'IconTint', 'iconTint', 'ColorFilter'
any suggestions?
These are the errors I'm getting
E/TransitionLayout: Custom Attribute "IconTint" not found on com.google.android.material.button.MaterialButton
E/TransitionLayout: com.google.android.material.button.MaterialButton must have a method setIconTint
E/TransitionLayout: no method setIconTinton View "f_editor_image_view_terminal"
MotionLayout's CustomAttribute use reflection to setValues on Views (roughly based on the Java beans conventions)
So if you say
<CustomAttribute motion:attributeName="foo" motion:customColorValue="#color/keyTextColor" />
It looks for a method setFoo(int value);
Unfortunately even though MaterialButton parses the xml android:iconTint="#FFF"
It does not have the method setIconTint(int color);
MotionLayout will also check for setFoo(Drawable()) and use a ColorDrawable
You can create a subclass of MaterialButton and implement the method needed
setInconTint(int color)
class MyButton extends MaterialButton {
public MyButton(#NonNull Context context) {
super(context);
}
public MyButton(#NonNull Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
}
public MyButton(#NonNull Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
void setIconTint(int color) {
ColorStateList colorStateList = new ColorStateList(new int[1][0],new int[]{color});
setIconTint(colorStateList);
}
}
This would then work with MotionLayout. This will create many objects during animation but they will be short lived.

Android custom image view using built-in attributes

It's my very first question here, so please go easy on me ;)
I've built my custom View class extending ImageView.
public class CustomImageView extends ImageView {
// ...
}
I have created a set of custom parameters for it in the shape of a <declare-styleable> item in the attrs.xml file.
<declare-styleable name="CustomImageView">
<attr name="angle" format="integer"/>
</declare-styleable>
I've figured out how to access (i.e. read from within the class and set from within the layout) these values.
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomImageView, 0, 0);
try {
a.getInt(R.styleable.CustomImageView_angle, 0);
} finally {
a.recycle();
}
So far, so easy. All of the above are directly taken from the guide.
However, I could not figure out how to access the inherited attributes of the ImageView class. Specifically, I want to read what was set as the src attribute of the ImageView. I'm assuming I have to use a different value for the second parameter of the obtainStyledAttributes(...) call, but I don't know what to use there and this obviously does not work:
a = context.getTheme().obtainStyledAttributes(attrs, ImageView, 0, 0);
So, how do I access the built-in attributes of my super class?
How do I get the int value (drawable res id) that was set for the android:src attribute?
Thanks for your help!
How do I get the int value (drawable res id) that was set for the
android:src attribute?
Use getAttributeResourceValue to get id of drawable :
public CustomImageView(Context context, AttributeSet attrs) {
super(context, attrs);
String android_schemas = "http://schemas.android.com/apk/res/android";
int srcId = attrs.getAttributeResourceValue(android_schemas, "src", -1);
}

Alter AttributeSet values in android

I am having custom view which will take attribute set(xml value) as constructor value
public CustomView(Context context) // No Attributes in this one.
{
super(context);
this(context, null, 0);
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
this(context, attrs, 0)
}
public CustomView(Context context, AttributeSet attrs, int default_style) {
super(context, attrs, default_style);
readAttrs(context, attrs, defStyle);
init();
}
In Fragment class i am setting the view as
CustomView customView = (CustomView) view.findViewById(R.id.customView);
where custom view contains various value such as height,width,padding etc.
i want to modify those values based on required condition and set it back to custom view.
I placed setting width height code in onDraw method and called invalidte view.
But above method will set the every time if i called invalidate method in CustomView class.
how to overcome this so that i can pass modified attribute set value in constructor only.?
Edit: I need to modify the view values(initialize with new values) which is set during attribute constructor so that i will get a refreshed view with a new values.
Override #OnDraw or 'Invalidate' is not a good function for me where inside invalidate i have written the methods which will execute in each second interval.
I see that your CustomView can have multiple attributes and you want to modify some of these attributes based on some condition and pass this in the constructor.
Few best practices while designing a custom view:
If you have custom attributes, make sure that you expose them via setters and getters. In your setter method, call invalidate();
Don't try modifying any attributes inside onDraw() or onMeasure() methods.
Try your best to avoid writing Custom constructors for your Custom View.
So the ideal way to solve your problem is to instantiate your CustomView and then modify the attributes, either externally (in your Activity or Fragment), or have a method inside the CustomView.java and then invoke it externally. Doing this will still give you the same result you are looking for.
So lets say you declared your custom attributes like this for view named StarsView
<declare-styleable name="StarsView">
<attr name="stars" format="integer" />
<attr name="score" format="float" />
</declare-styleable>
And you want to read attributes from something like this
<my.package..StarsView
app:stars="5"
app:score="4.6"
You do just this in constructor
public StarsView(Context context, AttributeSet attrs) {
super(context, attrs);
if(attrs != null) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.StarsView, defStyleAttr, 0);
stars = Tools.MathEx.clamp(1, 10, a.getInt(R.styleable.StarsView_stars, 5));
score = (int)Math.floor(a.getFloat(R.styleable.StarsView_score, stars) * 2f);
a.recycle(); // its important to call recycle after we are done
}
}
It's probably not the solution you were hoping for, but put a FrameLayout in your xml instead of the CustomView, and then create your CustomView programmatically with the FrameLayout as it's parent

Change multiple views background color

I have a lot of views using one and the same color as a background. I want to change the color of all views when I receive a call from the server programmatically. I don't want to call for every view
view.setBackgroundColor(new color);
Is there a way to change a color code that is in colors.xml.
Short answer: No, you can't. The resources are defined at compile time.
See this question for a similar case: How can I programmatically change the value of a color in colors.xml?
You can't replace the value of the color in the xml file. But you
can create different themes which are used in your application and
change the theme dynamically
See this tutorial:
http://www.developer.com/ws/android/changing-your-android-apps-theme-dynamically.html
What I end up doing is create a custom class that sets the color form preference. And use this class everywhere I want to change the color. And next time the view is drawn it gets the new color. Something like this:
public class ColoredToolbar extends android.support.v7.widget.Toolbar {
public ColoredToolbar(Context context) {
super(context);
setBackgroundColor(context);
}
public ColoredToolbar(Context context, AttributeSet attrs) {
super(context, attrs);
setBackgroundColor(context);
}
public ColoredToolbar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setBackgroundColor(context);
}
private void setBackgroundColor(Context context) {
int color = PreferenceHelper.getToolBarColor(context, Preferences.PREF_TITLE_BAR_COLOR_KEY);
this.setBackgroundColor(color);
}
}

ImageView Constructor usage

There are several constructors available for defining an ImageView.
For Example
1) public ImageView (Context context)
2) public ImageView (Context context, AttributeSet attrs)
3) public ImageView (Context context, AttributeSet attrs, int defStyle)**
I am confused in using 2nd and 3rd type of constructor.
basically i don't know what to pass in place of AttributeSet.
Kindly provide a coding example.
These constructors are defined in the View documentation. Here is a description of the parameters from View(Context, AttributeSet, int):
Parameters
context The Context the view is running in, through which it can access the current theme, resources, etc.
attrs The attributes of the XML tag that is inflating the view.
defStyle The default style to apply to this view. If 0, no style will be applied (beyond what is included in the theme). This may
either be an attribute resource, whose value will be retrieved from
the current theme, or an explicit style resource.
It's worth noting that you can pass null in place of an AttributeSet if you have no attributes to pass.
In terms of coding the AttributeSet, here's a bit of code I use for a custom TextView class I have:
public EKTextView(Context context, AttributeSet attrs) {
super(context, attrs);
// ...
if (attrs != null) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LocalTextView);
determineAttrs(context, a);
}
// ...
}
private void determineAttrs(Context c, TypedArray a) {
String font = a.getString(R.styleable.fontName);
if (font != null)
mTypeface = Typeface.createFromAsset(c.getAssets(), "fonts/" + font);
mCaps = a.getBoolean(R.styleable.allCaps, false);
}
As you can see, once you get a TypedArray from the attributes, you can just use its various methods to collect each of the attributes. Other code you may want to review is that of View(Context, AttributeSet, int) or Resources.obtainStyledAttributes(AttributeSet, int[], int, int).
Ways of creating imageView, ImageView with Context
ImageView image= new ImageView(context);
Here when you want set the values like height, width gravity etc you need to set
image.set****();
based on the number of attributes you need to use no of setXXX() methods,.
2.Using Attribute set
you can define set of attributes like height, width etc in your res/values folder in separate xml file, pass the xml file to getXml()
XmlPullParser parser = resources.getXml(yourxmlfilewithattribues);
AttributeSet attributes = Xml.asAttributeSet(parser);
ImageView image=new ImageView(context,attributes);
Here you can also define your custom attributes in your xml . and you can access the by using the methods provided by AttributeSet class example
getAttributeFloatValue(int index, float defaultValue)
//Return the float value of attribute at 'index'

Categories

Resources