Reference different raw resource depending on screen orientation - android

I would like to define raw resources in my dimens.xml file like I define margins, padding for different screen orientations.
I've tried this:
<item name="my_res" type="raw" format="string">R.raw.test</item>
But that doesn't seem to be working.
When I try to fetch id of that resource, it is not correct:
TypedValue out = new TypedValue();
getResources().getValue(R.raw.my_res, out, true);
int resId = out.resourceId;
Any suggestions how to han

Use Activity.getResources().getConfiguration().orientation for obtaining ORIENTATION_PORTRAIT and ORIENTATION_LANDSCAPE values indicating current orientation. Based on this, get appropiate raw resource.
TypedValue out = new TypedValue();
int resId;
if(Activity.getResources().getConfiguration().orientation == 1) { //1 for Portrait and 2 for Landscape
getResources().getValue(R.raw.my_res, out, true);
resId = out.resourceId;
} else {
getResources().getValue(R.raw.my_res_alternate, out, true);
resId = out.resourceId;
}
Do any necesary change, but this is the main idea.

Related

actionBarSize different in xml and code

I have a view with height defined as:
android:layout_height="?attr/actionBarSize"
Later on this view will have to be resized to a larger format and eventually back to the original, so in the onCreateView of the fragment I do:
final TypedArray styledAttributes = getActivity().getTheme().obtainStyledAttributes(
new int[] { android.R.attr.actionBarSize });
int actionBarSize = (int) styledAttributes.getDimension(0, 0);
styledAttributes.recycle()
Which, as far as I understand, should be the exact same value as i initially got in the XML.
This is however not the case, the value from the XML is 112 while in code it returns 96.
Anyone any clue why this is or what I am doing wrong?
doc for getDimension(int,int) says
Retrieve a dimensional unit attribute at index. Unit
conversions are based on the current DisplayMetrics
associated with the resources this TypedArray object
came from.
I think may be the displaymetrics associated with that does not work.
So try
float pixelvalue = styledAttributes.getDimensionPixelSize(0, 0);
float dpValue =pixelvalue/ getResources().getDisplayMetrics().density;
In case use ActionBarSherlock/AppCompat use:
?attr/actionBarSize
Why use?:
final int actionBarSize
why dont use?
actionBarSize = (int) styledAttributes.getDimension(0, 0);
styledAttributes.recycle();
this last option give you the value at runtime.

How to retrieve drawable from attributes reference

I defined theme and style inside my app. icons (drawable) are defined using reference in style file as
<attr name="myicon" format="reference" />
and style as
<style name="CustomTheme" parent="android:Theme.Holo">
<item name="myicon">#drawable/ajout_produit_light</item>
I need to retrieve the drawable programmatically to use the good image in a dialogfragment.
If I make like
mydialog.setIcon(R.style.myicon);
I get an id equals to 0, so no image
I tried to use something like
int[] attrs = new int[] { R.drawable.myicon};
TypedArray ta = getActivity().getApplication().getTheme().obtainStyledAttributes(attrs);
Drawable mydrawable = ta.getDrawable(0);
mTxtTitre.setCompoundDrawables(mydrawable, null, null, null);
I tried different things like that but result is always 0 or null :-/
How I can I do this ?
I found the solution on
Access resource defined in theme and attrs.xml android
TypedArray a = getTheme().obtainStyledAttributes(R.style.AppTheme, new int[] {R.attr.homeIcon});
int attributeResourceId = a.getResourceId(0, 0);
Drawable drawable = getResources().getDrawable(attributeResourceId);
Kotlin solution:
val typedValue = TypedValue()
context.theme.resolveAttribute(R.attr.yourAttr, typedValue, true)
val imageResId = typedValue.resourceId
val drawable = ContextCompat.getDrawable(context, imageResId) ?: throw IllegalArgumentException("Cannot load drawable $imageResId")
With the assumption your context (activity) is themed the way you want it, you can use resolveAttribute on the theme:
TypedValue themedValue = new TypedValue();
this.getTheme().resolveAttribute(R.attr.your_attribute, themedValue, true);
myView.setBackgroundResource(themedValue.resourceId);
So in your case it would look something like this:
TypedValue themedValue = new TypedValue();
this.getTheme().resolveAttribute(R.attr.myicon, themedValue, true);
Drawable mydrawable = AppCompatResources.getDrawable(this, themedValue.resourceId);
mTxtTitre.setCompoundDrawables(mydrawable, null, null, null);
In the examples this would be your activity. If you're not in an activity get a valid context.
It would seem as though you are trying to set the icon of your myDialog using a resource and are trying to access it through R.style but your other code segment leads me to believe that you have the resource located in R.drawable
With that in mind you should be able to get the effect you want with myDialog.setIcon(R.drawable.myicon);

Android: how to get value of an attribute in code?

I would like to retrieve the int value of textApperanceLarge in code. I believe that the below code is going in the right direction, but can't figure out how to extract the int value from the TypedValue.
TypedValue typedValue = new TypedValue();
((Activity)context).getTheme().resolveAttribute(android.R.attr.textAppearanceLarge, typedValue, true);
Your code only gets the resource ID of the style that the textAppearanceLarge attribute points to, namely TextAppearance.Large as Reno points out.
To get the textSize attribute value from the style, just add this code:
int[] textSizeAttr = new int[] { android.R.attr.textSize };
int indexOfAttrTextSize = 0;
TypedArray a = context.obtainStyledAttributes(typedValue.data, textSizeAttr);
int textSize = a.getDimensionPixelSize(indexOfAttrTextSize, -1);
a.recycle();
Now textSize will be the text size in pixels of the style that textApperanceLarge points to, or -1 if it wasn't set. This is assuming typedValue.type was of type TYPE_REFERENCE to begin with, so you should check that first.
The number 16973890 comes from the fact that it is the resource ID of TextAppearance.Large
Using
TypedValue typedValue = new TypedValue();
((Activity)context).getTheme().resolveAttribute(android.R.attr.textAppearanceLarge, typedValue, true);
For the string :
typedValue.string
typedValue.coerceToString()
For other data :
typedValue.resourceId
typedValue.data // (int) based on the type
In your case what it returns is of the TYPE_REFERENCE.
I know it should point to TextAppearance.Large
Which is :
<style name="TextAppearance.Large">
<item name="android:textSize">22sp</item>
<item name="android:textStyle">normal</item>
<item name="android:textColor">?textColorPrimary</item>
</style>
Credit goes to Martin for resolving this :
int[] attribute = new int[] { android.R.attr.textSize };
TypedArray array = context.obtainStyledAttributes(typedValue.resourceId, attribute);
int textSize = array.getDimensionPixelSize(0, -1);
Or in kotlin:
fun Context.dimensionFromAttribute(attribute: Int): Int {
val attributes = obtainStyledAttributes(intArrayOf(attribute))
val dimension = attributes.getDimensionPixelSize(0, 0)
attributes.recycle()
return dimension
}
It seems to be an inquisition on the #user3121370's answer. They burned down. :O
If you just need the get a dimension, like a padding, minHeight (my case was: android.R.attr.listPreferredItemPaddingStart). You can do:
TypedValue typedValue = new TypedValue();
((Activity)context).getTheme().resolveAttribute(android.R.attr.listPreferredItemPaddingStart, typedValue, true);
Just like the question did, and then:
final DisplayMetrics metrics = new android.util.DisplayMetrics();
WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
wm.getDefaultDisplay().getMetrics(metrics);
int myPaddingStart = typedValue.getDimension( metrics );
Just like the removed answer. This will allow you to skip handling device pixel sizes, because it uses the default device metric. The return will be float, and you should cast to int.
Becareful to the type you are trying to get, like resourceId.
this is my code.
public static int getAttributeSize(int themeId,int attrId, int attrNameId)
{
TypedValue typedValue = new TypedValue();
Context ctx = new ContextThemeWrapper(getBaseContext(), themeId);
ctx.getTheme().resolveAttribute(attrId, typedValue, true);
int[] attributes = new int[] {attrNameId};
int index = 0;
TypedArray array = ctx.obtainStyledAttributes(typedValue.data, attributes);
int res = array.getDimensionPixelSize(index, 0);
array.recycle();
return res;
}
// getAttributeSize(theme, android.R.attr.textAppearanceLarge, android.R.attr.textSize) ==> return android:textSize

What is the size of ActionBar in pixels?

I need to know the exact size of ActionBar in pixels so to apply correct background image.
To retrieve the height of the ActionBar in XML, just use
?android:attr/actionBarSize
or if you're an ActionBarSherlock or AppCompat user, use this
?attr/actionBarSize
If you need this value at runtime, use this
final TypedArray styledAttributes = getContext().getTheme().obtainStyledAttributes(
new int[] { android.R.attr.actionBarSize });
mActionBarSize = (int) styledAttributes.getDimension(0, 0);
styledAttributes.recycle();
If you need to understand where this is defined:
The attribute name itself is defined in the platform's /res/values/attrs.xml
The platform's themes.xml picks this attribute and assigns a value to it.
The value assigned in step 2 depends on different device sizes, which are defined in various dimens.xml files in the platform, ie. core/res/res/values-sw600dp/dimens.xml
From the de-compiled sources of Android 3.2's framework-res.apk, res/values/styles.xml contains:
<style name="Theme.Holo">
<!-- ... -->
<item name="actionBarSize">56.0dip</item>
<!-- ... -->
</style>
3.0 and 3.1 seem to be the same (at least from AOSP)...
To get the actual height of the Actionbar, you have to resolve the attribute actionBarSize at runtime.
TypedValue tv = new TypedValue();
context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true);
int actionBarHeight = getResources().getDimensionPixelSize(tv.resourceId);
One of the Honeycomb samples refers to ?android:attr/actionBarSize
I needed to do replicate these heights properly in a pre-ICS compatibility app and dug into the framework core source. Both answers above are sort of correct.
It basically boils down to using qualifiers. The height is defined by the dimension "action_bar_default_height"
It is defined to 48dip for default. But for -land it is 40dip and for sw600dp it is 56dip.
If you're using the compatibility ActionBar from the recent v7 appcompat support package, you can get the height using
#dimen/abc_action_bar_default_height
Documentation
With the new v7 support library (21.0.0) the name in R.dimen has changed to #dimen/abc_action_bar_default_height_material.
When upgrading from a previous version of the support lib you should therefore use that value as the actionbar's height
If you are using ActionBarSherlock, you can get the height with
#dimen/abs__action_bar_default_height
#AZ13's answer is good, but as per the Android design guidelines, the ActionBar should be at least 48dp high.
Accepted answer in Kotlin :
val Context.actionBarSize
get() = theme.obtainStyledAttributes(intArrayOf(android.R.attr.actionBarSize))
.let { attrs -> attrs.getDimension(0, 0F).toInt().also { attrs.recycle() } }
Usage :
val size = actionBarSize // Inside Activity
val size = requireContext().actionBarSize // Inside Fragment
val size = anyView.context.actionBarSize // Inside RecyclerView ViewHolder
public int getActionBarHeight() {
int actionBarHeight = 0;
TypedValue tv = new TypedValue();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
if (getTheme().resolveAttribute(android.R.attr.actionBarSize, tv,
true))
actionBarHeight = TypedValue.complexToDimensionPixelSize(
tv.data, getResources().getDisplayMetrics());
} else {
actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data,
getResources().getDisplayMetrics());
}
return actionBarHeight;
}
The Class Summary is usually a good place to start. I think the getHeight() method should suffice.
EDIT:
If you need the width, it should be the width of the screen (right?) and that can be gathered like this.
On my Galaxy S4 having > 441dpi > 1080 x 1920 >
Getting Actionbar height with getResources().getDimensionPixelSize I got 144 pixels.
Using formula px = dp x (dpi/160), I was using 441dpi, whereas my device lies
in the category 480dpi. so putting that confirms the result.
I did in this way for myself, this helper method should come in handy for someone:
private static final int[] RES_IDS_ACTION_BAR_SIZE = {R.attr.actionBarSize};
/**
* Calculates the Action Bar height in pixels.
*/
public static int calculateActionBarSize(Context context) {
if (context == null) {
return 0;
}
Resources.Theme curTheme = context.getTheme();
if (curTheme == null) {
return 0;
}
TypedArray att = curTheme.obtainStyledAttributes(RES_IDS_ACTION_BAR_SIZE);
if (att == null) {
return 0;
}
float size = att.getDimension(0, 0);
att.recycle();
return (int) size;
}

Android: how to get value of "listPreferredItemHeight" attribute in code?

The below code gives Resources$NotFoundException
TypedValue value = new TypedValue();
((Activity)context).getResources().getValue(android.R.attr.listPreferredItemHeight, value, true);
EDIT: More code added in response to answer.
When I run the below code, all members of displayMetrics are 0. As is ret.
TypedValue value = new TypedValue();
DisplayMetrics displayMetrics = new DisplayMetrics();
((Activity)context).getTheme().resolveAttribute(android.R.attr.listPreferredItemHeight, value, true);
float ret = value.getDimension(displayMetrics);
This works:
TypedValue value = new TypedValue();
((Activity)context).getTheme().resolveAttribute(android.R.attr.listPreferredItemHeight, value, true);
EDIT: You get zero because haven't initialized the DisplayMetrics instance properly. It needs a frame of reference (a display) to do any meaningful conversion.
android.util.TypedValue value = new android.util.TypedValue();
boolean b = getTheme().resolveAttribute(android.R.attr.listPreferredItemHeight, value, true);
String s = TypedValue.coerceToString(value.type, value.data);
android.util.DisplayMetrics metrics = new android.util.DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
float ret = value.getDimension(metrics);
On my Nexus 1 s is 64.0dip and ret is 96.
Another answer
public float getItemHeight() {
TypedValue value = new TypedValue();
DisplayMetrics metrics = new DisplayMetrics();
context.getTheme().resolveAttribute(
android.R.attr.listPreferredItemHeight, value, true);
((WindowManager) (context.getSystemService(Context.WINDOW_SERVICE)))
.getDefaultDisplay().getMetrics(metrics);
return TypedValue.complexToDimension(value.data, metrics);
}
it maybe more useful.
Femi's answer was very helpful. Without wanting to detract from his answer, I've taken the logic and placed it in a library convenience method that you should be able to plug-and-play. I plan on updating the code with other attribute methods over time. I hope it proves useful to someone.
(Note that I discovered Resources.getDisplayMetrics() seems to be an easier way to return display metrics rather than querying the WindowManager.)
The shortest answer (without DisplayMetrics):
TypedValue typedValue = new TypedValue();
context.getTheme().resolveAttribute(android.R.attr.listPreferredItemHeight, typedValue, true);
int height = TypedValue.complexToDimensionPixelSize(typedValue.data, context.getResources().getDisplayMetrics());

Categories

Resources