Get size of UI before actually creating one? - android

I am working on an Android app that is largely driven by code, not xml.
The Adapter for a ListView wants to know the height of the item. But this in turn could depend on the size of UI elements within the item. For example, if the item contains a checkbox, the size of the checkbox could influence the layout of the list item, which in turn could change the height, depending on whether or not a line wrap became necessary.
Question -- is there a way to get the size of an Android UI element without actually creating it? Similar to the way one can use a Paint or TextPaint object to get the size of text before it is drawn.

Without creating it? No, but you could use the MeasureSpec class and measure the View manually after you create it. Why do you need to know the exact size? Can't you just set the LayoutParams to MATCH_PARENT (width) and WRAP_CONTENT (height) for your case?
That said, if you do need to know, you could use the width of your ListView for the width MeasureSpec, and then UNSPECIFIED for the height MeasureSpec:
// Tell the View it should be exactly as wide as the ListView...
int widthSpec = MeasureSpec.makeMeasureSpec(listViewWidth, MeasureSpec.EXACTLY);
// ... and as tall as it wants to be ...
int heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
// ... measure it with these constraints ...
item.measure(widthSpec, heightSpec);
// ... and retrieve the measured height.
int itemHeight = item.getMeasuredHeight();

Related

How to know LayoutParams of View before measurement?

I have custom view with child items, which are configureable via xml. However they are can be configurable in runtime via something like a Configuration class. After that I just notify parent view about changes and all is ok.BTW. My question in fact touches measurement: I can change child items size in runtime, but for the first launch I want to set to all of them size (width and height) accordingly to layout params defined in xml.
Maybe some code will add more clarification to you.
protected int getItemWidth() {
if (cell != null) {
int width = cell.getWidth();
return width == 0 ? <layout_width_defined_in_xml> : ScreenUtils.convertToDp(context, width);
} else {
return canvasWidth;
}
}
So, I want to know. Is possible to get layout params before measurement? And how to that?
The size defined in XML isn't always the right size the view should have when it's actually laid out. For example, a child of a LinearLayout may have android:layout_width="0", but might have nonzero width because of android:layout_weight. (There are other examples as well with other kinds of layouts.) Additionally, the values match_parent and wrap_content map to negative integer values in java code, which I don't think is helpful to you here.
If your custom view is interested in measuring and positioning child views, you should be overriding onMeasure() and onLayout(). If you aren't doing that or if you don't need to do that, getWidth() and getHeight() will tell you a view's actual size, and getMeasuredWidth() and getMeasuredHeight() will tell you the measured size (which can differ from the actual size). THe only caveat is that you have to wait for the first measure/layout before calling those 4 methods because otherwise those methods all return zero.
If you do want to inspect the layout parameters of a view, you can do
LayoutParams params = view.getLayoutParams();
int width = params.width;
int height = params.height;
As noted, either or both of those may be negative. You can compare them to LayoutParams.MATCH_PARENT and LayoutParams.WRAP_CONTENT to check for these cases, but again I'm not sure this is helpful to you if you aren't implementing onMeasure() and onLayout().
You can do this in callback ViewTreeObserver.OnGlobalLayoutListener. You can get view dimensions here and set size other views with these dimensions.

Android setMaxLines with animation

I'm using a TextView to be viewed in ListView item, when that item is clicked I need that text to completely be viewed instead of just first 2 lines.
What I'm doing now is changing maxLines value from 2 (the initial value) to the maximum integer value.
I need this to be done with expand animation. I already know how to expand it, but I only need to find the new height such that I can simply call the expand method.
Update:
I'm using this code to solve my problem, but the returned full height is smaller than the actual one. I think it's px and dp issue:
public int getFullHeight(TextView tv) {
Context context = tv.getContext();
TextView textView = new TextView(context);
textView.setText(tv.getText().toString());
textView.setTypeface(tv.getTypeface());
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, tv.getTextSize());
int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(tv.getLayoutParams().width, View.MeasureSpec.EXACTLY);
int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
textView.measure(widthMeasureSpec, heightMeasureSpec);
return textView.getMeasuredHeight();
}
Given that tv is the original TextView that's with 2 lines.
If I change COMPLEX_UNIT_PX to COMPLEX_UNIT_DIP then it gets larger than the full size, with a white space at the bottom.
Best solution I can find is this:
Measuring text height to be drawn on Canvas ( Android )
Or here: http://egoco.de/post/19077604048/calculating-the-height-of-text-in-android
What they are doing is, creating a paint object with specified width, placing the text and style to use in it and then geting the boundaries.
Hope that helps

Get size of GridView when creating items within its adapter

I want to arrange a set of custom widgets inside a GridView. There are predefined templates which describe a count of elements and arrangement config. Max width and heigh for each of them have to be provided in order to avoid scrolling. How can I get a size of the displayed GridView when computing items size in adapter's "GetView" method?
You have access to few functions in order to get a GridView Height and Width as any other View. Look at the documentation here.
The size of a view is expressed with a width and a height. A view
actually possess two pairs of width and height values.
The first pair is known as measured width and measured height. These
dimensions define how big a view wants to be within its parent (see
Layout for more details.) The measured dimensions can be obtained by
calling getMeasuredWidth() and getMeasuredHeight().
The second pair is simply known as width and height, or sometimes
drawing width and drawing height. These dimensions define the actual
size of the view on screen, at drawing time and after layout. These
values may, but do not have to, be different from the measured width
and height. The width and height can be obtained by calling getWidth()
and getHeight().
Try doing a quick search on their doc next time, even if it's Xamarin, the Android doc is pretty reliable and you only need some adjustment to make it work.
(e.g.) : grivView.Width; instead of gridView.getWidth(); one being a property on Xamarin to follow C# standards, the other is a function.

TextView.getMinHeight() in < 16 API

TextView.getMinHeight() appears in API 16. But TextView.setMinHeight() appears in API 1. Where is any possible way to get min height in pre API 16 version without reflection?
Use ViewCompat.getMinimumHeight(view) from support-v4 library.
There's no way to get it without reflection.
The field is called mMaximum. It can hold a value in pixels or in lines of text, that's why it's not called mMaxHeight.
Saving the value in setMaxHeight() is not ideal, because there's also setMaxLines() method, which changes the max mode and effectively clears the max height value. You would have to overload all methods writing mMaximum field.
short answer:
View.getLayoutParams().height
View.getLayoutParams().width
other possibilities :
The size of a view is expressed with a width and a height. A view actually possess two pairs of width and height values.
The first pair is known as measured width and measured height. These dimensions define how big a view wants to be within its parent (see Layout for more details.) The measured dimensions can be obtained by calling getMeasuredWidth() and getMeasuredHeight().
The second pair is simply known as width and height, or sometimes drawing width and drawing height. These dimensions define the actual size of the view on screen, at drawing time and after layout. These values may, but do not have to, be different from the measured width and height. The width and height can be obtained by calling getWidth() and getHeight().
ways:
using the famous OnGlobalLayoutListener
This is one of the most used mechanisms to get the view dimensions. You attach a Global Layout Listener to the view hierarchy. It helps you actually get the width of all the views in your view heirarchy:
by forcing a measurement of the View
View.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
int widht = View.getMeasuredWidth();
int height = View.getMeasuredHeight();

What are widthMeasureSpec and heightMeasureSpec in Android custom Views?

I have seen a lot of examples of creating custom views and layouts in android. What I've learned from them is that the measure (as said on Android developer's site) method is onMeasure(), which has widthMeasureSpec and heightMeasureSpec as parameters.
What is the actual meaning of those parameters?
What are their initial values?
With what values they are called if the custom view that I am creating is the parent view for my activity?
I am really very confused about these questions.
widthMeasureSpec and heightMeasureSpec are compound variables. Meaning while they are just plain old ints, they actually contain two separate pieces of data.
The first part of data stored in these variables is the available space (in pixels) for the given dimension.
You can extract this data using this convenience method:
int widthPixels = View.MeasureSpec.getSize( widthMeasureSpec );
The second piece of data is the measure mode, it is stored in the higher order bits of the int, and is one of these possible values:
View.MeasureSpec.UNSPECIFIED
View.MeasureSpec.AT_MOST
View.MeasureSpec.EXACTLY
You can extract the value with this convenience method:
int widthMode = View.MeasureSpec.getMode( widthMeasureSpec );
You can do some logic, change one or both of these, and then create a new meassureSpec using the last convenience method:
int newWidthSpec = View.MeasureSpec.makeMeasureSpec( widthPixels, widthMode );
And pass that on down to your children, usually by calling super.onMeasure( widthMeasureSpec, heightMeasureSpec );
In onMeasure() the MeasureSpec pattern serves the purpose of passing in the maximum allowed space your view and it's children are allowed to occupy. It also uses the spec mode as a way of placing some additional constrains on the child views, informing them on how they are allowed to use the available space.
A good example of how this is used is Padding. ViewGroups take the available width and height, and subtract out their padding, and then create a new meassureSpec, thus passing a slightly smaller area to their children.
This article will be helpful for you. I'm answering your question from the context of the article.
1. What is the actual meaning of those parameters?
Answer:
widthMeasureSpec Horizontal space requirements as imposed by the parent view to the child view.
heightMeasureSpec Vertical space requirements as imposed by the parent view to the child view
2. What are their initial values?
Answer:
when MODE_SHIFT = 30 when values are -
MeasureSpec.UNSPECIFIED = 0 << MODE_SHIFT = 0
MeasureSpec.EXACTLY = 1 << MODE_SHIFT = 1073741824
MeasureSpec.AT_MOST = 2 << MODE_SHIFT = 2147483648
3. With what values they are called if the custom view that I am creating is the parent view for my activity?
Answer:
It will depend on what height and width you give in the parent view. You will get a good insight about it in the last part of the article which also shows a chart below I mentioned -

Categories

Resources