actionBarSize different in xml and code - android

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.

Related

Android get textview width and height before the setting text and rendering

I am trying to get the width of a textview setting the text. Here's the Code I am using:
public int getTextViewEffectedWidth(TextView textView, String content){
Rect bounds = new Rect();
Paint paint = textView.getPaint();
paint.getTextBounds(content, 0, content.length(), bounds);
return bounds.width();
}
But this method returns larger width. Example:
I need set in textview value "6978"
This method was calculate width = 46 (By the way returned value in dp or sp ? I set in dp, cause in px this value in not enough.)
If I set textview's width 46 dp or sp, TextView will has extra place
I need to get the width value which would be consistent with width="wrap_content"
TextView size and font have default values.
try this,you will get the value in pixel;
int width=convertToPixel(textView.getWidth());
int height=convertToPixel(textView.getHeight());
private int convertToPixel(int n) {
Resources r = getResources();
float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, n, r.getDisplayMetrics());
return (int) px;
}
I know it's a little while after your request, but are you running the check in an OnGlobalLayoutListener?
If not, then the view won't be completely drawn on the screen, and you won't have the dimensions available.
Inside the onGlobalLayout() you can called measuredWidth and measuredHeight.
I hope this helps, if not you, then someone else.

How can I set the top padding of a ListView programmatically? [duplicate]

I am developing Android v2.2 app.
I have a Fragment. In the onCreateView(...) callback of my fragment class, I inflate an layout to the fragment like below:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.login, null);
return view;
}
The above inflated layout file is (login.xml):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Username" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Username" />
</LinearLayout>
I would like to set a paddingTop to the above <LinearLayout> element , and I want to do it in the Java code instead of do it in xml.
How to set paddingTop to <LinearLayout> in my fragment Java class code ??
view.setPadding(0,padding,0,0);
This will set the top padding to padding-pixels.
If you want to set it in dp instead, you can do a conversion:
float scale = getResources().getDisplayMetrics().density;
int dpAsPixels = (int) (sizeInDp*scale + 0.5f);
To answer your second question:
view.setPadding(0,padding,0,0);
like SpK and Jave suggested, will set the padding in pixels. You can set it in dp by calculating the dp value as follows:
int paddingDp = 25;
float density = context.getResources().getDisplayMetrics().density
int paddingPixel = (int)(paddingDp * density);
view.setPadding(0,paddingPixel,0,0);
If you store the padding in resource files, you can simply call
int padding = getResources().getDimensionPixelOffset(R.dimen.padding);
It does the conversion for you.
Using Kotlin and the android-ktx library, you can simply do
view.updatePadding(top = 42)
See docs here
You can set padding to your view by pro grammatically throughout below code -
view.setPadding(0,1,20,3);
And, also there are different type of padding available -
Padding
PaddingBottom
PaddingLeft
PaddingRight
PaddingTop
These, links will refer Android Developers site. Hope this helps you lot.
Using TypedValue is a much cleaner way of converting to pixels compared to manually calculating:
float paddingDp = 10f;
// Convert to pixels
int paddingPx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, paddingDp, context.getResources().getDisplayMetrics());
view.setPadding(paddingPx, paddingPx, paddingPx, paddingPx);
Essentially, TypedValue.applyDimension converts the desired padding into pixels appropriately depending on the current device's display properties.
For more info see: TypedValue.applyDimension Docs.
Kotlin; extension function
fun Float.px(m: DisplayMetrics!): Int
get() = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this, m).toInt()
...
val pad = 10.0f.px
use below method for setting padding dynamically
setPadding(int left, int top, int right, int bottom)
Example :
view.setPadding(2,2,2,2);
Here you can see in which section the padding is applied
bidding.subHeader.tvSubHeader.setPadding(0, 5, 0, 0);
Someone edited this answer, but I added an image that had been removed before, here it is again
Step 1: First, take the padding value as an integer.
int padding = getResources().getDimensionPixelOffset(R.dimen.padding);
or int padding = 16; [Use any method]
Step 2: Then assign the padding value to the layout.
layout.setPadding(padding, padding, padding, padding);
layout.setPadding(padding_left, padding_top, padding_right, padding_bottom);
All side different padding can be assigned. layout.setPadding(16, 10, 8, 12);
For removing padding (No Padding) set padding values as 0,
layout.setPadding(0, 0, 0, 0);
Write Following Code to set padding, it may help you.
TextView ApplyPaddingTextView = (TextView)findViewById(R.id.textView1);
final LayoutParams layoutparams = (RelativeLayout.LayoutParams) ApplyPaddingTextView.getLayoutParams();
layoutparams.setPadding(50,50,50,50);
ApplyPaddingTextView.setLayoutParams(layoutparams);
Use LinearLayout.LayoutParams or RelativeLayout.LayoutParams according to parent layout of the child view
Context contect=MainActivity.this;
TextView tview=new TextView(context);
tview.setPaddingRelative(10,0,0,0);
The best way is not to write your own funcion.
Let me explain the motivaion - please lookup the official Android source code.
In TypedValue.java we have:
public static int complexToDimensionPixelSize(int data,
DisplayMetrics metrics)
{
final float value = complexToFloat(data);
final float f = applyDimension(
(data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK,
value,
metrics);
final int res = (int) ((f >= 0) ? (f + 0.5f) : (f - 0.5f));
if (res != 0) return res;
if (value == 0) return 0;
if (value > 0) return 1;
return -1;
}
and:
public static float applyDimension(int unit, float value,
DisplayMetrics metrics)
{
switch (unit) {
case COMPLEX_UNIT_PX:
return value;
case COMPLEX_UNIT_DIP:
return value * metrics.density;
case COMPLEX_UNIT_SP:
return value * metrics.scaledDensity;
case COMPLEX_UNIT_PT:
return value * metrics.xdpi * (1.0f/72);
case COMPLEX_UNIT_IN:
return value * metrics.xdpi;
case COMPLEX_UNIT_MM:
return value * metrics.xdpi * (1.0f/25.4f);
}
return 0;
}
As you can see, DisplayMetrics metrics can differ, which means it would yield different values across Android-OS powered devices.
I strongly recommend putting your dp padding in dimen xml file and use the official Android conversions to have consistent behaviour with regard to how Android framework works.
Using Jave's solution.
public static int getResourceDimension(Context context, String name, String defType, String defPackage) {
int sizeInDp = 0;
int resourceId = context.getResources().getIdentifier(name, defType, defPackage);
if (resourceId > 0) {
sizeInDp = context.getResources().getDimensionPixelSize(resourceId);
}
float scale = context.getResources().getDisplayMetrics().density;
int dpAsPixels = (int) (sizeInDp*scale + 0.5f);
return dpAsPixels;
}
then call when needed.
int statusBarHeight = getResourceDimension(getContext(), "status_bar_height",
"dimen", "android");
statusBarHeight = (int) (statusBarHeight + getResources().getDimension(R.dimen.fragment_vertical_padding));
view.setPadding(0, statusBarHeight, 0, 0);
While padding programmatically, convert to density related values by converting pixel to Dp.
binding.appBarMain.toolbar.setOnApplyWindowInsetsListener { _, insets ->
val statusBarSize: Int =
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
insets.getInsets(WindowInsets.Type.systemBars()).top
} else {
insets.systemWindowInsetTop
}
binding.appBarMain.appBarLayout.setPadding(0, statusBarSize, 0, 0)
return#setOnApplyWindowInsetsListener insets
}

Why I'm getting different results when running TextView.measure() in code, from what I see rendered on screen

I'm now trying to resolve an issue with somehow overlapping text in TextView.
I've posted a question about that , but I've also tried to solve it myself. I decided to count the amount of text which causes the textview to break the line. I came up with this unpolished code, which basically should inflate the view, set it's layout params according to the displayed size and then run onmeasure and return lineCount. I plan than to use probably binary search to find exact text length which fits into the textview, but even before I've just tried to run the code and see how it behaves. It's kind of weird, because it gives me different results, than what I see on screen than. I even tried to alter the textsize according to scaled density, because I wasn't sure whether it's been taken into account.
Here is the code. It returns three,but when I render the layout to screen the text takes up only two lines.
public int getCountOfLines(Context context, int widgetDp){
LayoutInflater mLayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
LinearLayout layout = (LinearLayout) mLayoutInflater.inflate(R.layout.event_basic_large ,null, false);
TextView titleTextView = (TextView) layout.findViewById(R.id.itemTitle);
titleTextView.setText(TEST_TEXT);
float density = context.getResources().getDisplayMetrics().density;
float textDensity = context.getResources().getDisplayMetrics().scaledDensity;
titleTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, titleTextView.getTextSize()/density*textDensity);
layout.setLayoutParams(
new LinearLayout.LayoutParams(
(int) (widgetDp*density),
ViewGroup.LayoutParams.WRAP_CONTENT)
);
layout.measure(View.MeasureSpec.makeMeasureSpec(
(int) (widgetDp*density), View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
);
Log.d(TAG, titleTextView.getLineCount() + " lines, width "+titleTextView.getMeasuredWidth());
return titleTextView.getLineCount();
}
I ran into this a while back and after searching and trying finally got the following function to work:
public int getLineCount(String testString, float textSize,
float width) {
Rect bounds = new Rect();
Paint paint = new Paint();
paint.setTypeface(<font>);//set font that you are using for this
paint.setTextSize(textSize);
paint.getTextBounds(testString, 0, testString.length(), bounds);
return (int) Math.ceil(bounds.width() / width);
}
This function uses textSize and width to give number of lines.
This functions give number of line in a textview before it is displayed.

Setting textSize programmatically

textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, getResources().getDimension(R.dimen.result_font));
The following code works, but the R.dimen.result_font is taken as a much bigger value than it really is. Its maybe about 18sp-22sp or 24sp according to the screen size ... But the size set here is at least about 50sp. Can someone please recommend something ?
You have to change it to TypedValue.COMPLEX_UNIT_PX because getDimension(id) returns a dimen value from resources and implicitly converted to px.
Java:
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
getResources().getDimension(R.dimen.result_font));
Kotlin:
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
resources.getDimension(R.dimen.result_font))
Requirement
Suppose we want to set textView Size programmatically from a resource file.
Dimension resource file (res/values/dimens.xml)
<resources>
<dimen name="result_font">16sp</dimen>
</resources>
Solution
First get dimen value from resource file into a variable "textSizeInSp".
int textSizeInSp = (int) getResources().getDimension(R.dimen.result_font);
Next convert 16 sp value into equal pixels.
for that create a method.
public static float convertSpToPixels(float sp, Context context) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, context.getResources().getDisplayMetrics());
}
Let's set TextSize,
textView.setTextSize(convertSpToPixels(textSizeInSp , getApplicationContext()));
All together,
int textSizeInSp = (int) getResources().getDimension(R.dimen.result_font);
textView.setTextSize(convertSpToPixels(textSizeInSp , getApplicationContext()));

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

Categories

Resources