Android: Problem with onMeasure() - android

I made a custom view. If I add the view to the layout XML file and I set the height to fill_parent "specSize" return 0. Why?
Code:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int measuredHeight = 90;
int specMode = MeasureSpec.getMode(heightMeasureSpec);
int specSize = MeasureSpec.getSize(MeasureSpec.getMode(heightMeasureSpec));
if(specMode != MeasureSpec.UNSPECIFIED){
measuredHeight = specSize;
}
setMeasuredDimension(60, measuredHeight);
}
Does anyone know how I can get the height of fill_parent?

You don't need to call MeasureSpec.getMode inside of call to 'getSize' whole idea of measure spec is to combine way of measuring ( knowing as Spec) and associated Size. See documentation for MeasureSpec.makeMeasureSpec method.So correct code will look something like:
int widthSpec = MeasureSpec.getMode(widthMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);

The correct code will be:
int specMode = MeasureSpec.getMode(heightMeasureSpec); ----This was already correct
int specSize = MeasureSpec.getSize(heightMeasureSpec); ----This is corrected.

Related

How to know if widgets width is set to wrap_content

I am creating a custom view which extends LinearLayout. I'm adding some shapes to the linear layout, currently with a fixed value of space between them. I'm doing so by defining a LayoutParams and setting the margins to create the space between the shapes.
What I want to do is span them at an equal space across the entire screen so they would fill it, but only if the width of the view is set to either match_parent or fill_parent. If it's set to wrap_content then the original fixed value of space should be set.
I've tried doing:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
spaceBetweenShapesPixels = (parentWidth - shapeWidth * numberOfShapes) / numberOfShapess;
}
However, the method seems to be called twice - Once for the width and height of the parent and after that for the View's itself and when it's for the view itself, the space gets a 0 value.
So how can I just make this logic:
if(width is wrap_content)
{
space = 10;
}
else
{
space = (parentWidth - shapeWidth * numberOfShapes) / numberOfShapess;
}
You should use WidthMode and HeightMode
In the onMeasure() method. Below is sample a from one of my projects
#Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int measuredWidth = 0, measuredHeight = 0;
if (widthMode == MeasureSpec.EXACTLY || widthMode == MeasureSpec.AT_MOST) {
measuredWidth = MeasureSpec.getSize(widthMeasureSpec);
}
if (heightMode == MeasureSpec.EXACTLY) {
measuredHeight = MeasureSpec.getSize(heightMeasureSpec);
} else if (heightMode == MeasureSpec.AT_MOST) {
double height = MeasureSpec.getSize(heightMeasureSpec) * 0.8;
measuredHeight = (int) height;// + paddingTop + paddingBottom;
}
}
MeasureSpec.EXACTLY - A view should be exactly this many pixels regardless of how big it actually wants to be.
MeasureSpec.AT_MOST - A view can be this size or smaller if it measures out to be smaller.
MeasureSpec.UNSPECIFIED - A view can be whatever size it needs to be in order to show the content it needs to show.
Refer this for more details https://stackoverflow.com/a/16022982/2809326

How to cut off an unused space in a custom view?

I have a custom View which has bigger height than its inner drawn content. I tried to set desired content height manually in code like this:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int chosenWidth = chooseDimension(widthMode, widthSize);
int chosenHeight = chooseDimension(heightMode, heightSize);
int chosenDimension = Math.min(chosenWidth, chosenHeight);
centerX = chosenDimension / 2 - offsetCenterX;
centerY = chosenDimension / 2 - offsetCenterY;
setMeasuredDimension(chosenDimension, chosenDimension - 200); //IN HERE I`M TRYING TO CROP THE VIEWS HEIGHT
}
But it appears that my View scales down. I do not need this.
My solution to this was to reset ALL the dimensions in dimen.xml, but it kinda wrong. Any idea how to crop it in a right and easy way?
Here it is a picture what I want to cut off
Well, I would not have to cut off that space. Just set the correct values in onMesaure(). And to scale all dimens in dimens.xml

How to set CustomView size?

I am creating a triangle (Custom View) and then adding it to the parent view (RelativeLayout). i am facing problem here was view taking full screen of parent, how can i set the size of custom view upto that boundaries. triangle extends from view and it has touch listeners. dynamically i'm changing the size of the triangle.
i was added onMeasure() to that view but it takes some fixed amount of width and height..
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Log.d(TAG, "Width spec: " + MeasureSpec.toString(widthMeasureSpec));
Log.d(TAG, "Height spec: " + MeasureSpec.toString(heightMeasureSpec));
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int chosenWidth = chooseDimension(widthMode, widthSize);
int chosenHeight = chooseDimension(heightMode, heightSize);
int chosenDimension = Math.min(chosenWidth, chosenHeight);
setMeasuredDimension(chosenDimension, chosenDimension);
}
i want set the width and height of custom view depending on the size of view when user change how much it has. look at the image.
It does not matter where the points are. You can draw the triangle of any orientation. But the custom view will always be a rectangular. If you do not draw anything outside the triangle the view will appear triangular.

onMeasure(...) being passed MeasureSpec.EXACTLY, apparently wrongly

I've created a custom View that implements onMeasure:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
float width = MeasureSpec.getSize(widthMeasureSpec);
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
float height = MeasureSpec.getSize(heightMeasureSpec);
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
float nominalHeight = getResources().getInteger(R.integer.nominalheight);
float nominalWidth = getResources().getInteger(R.integer.nominalwidth);
float aspectRatio = nominalWidth / nominalHeight;
if( width / height > aspectRatio //too wide
&& (
widthMode == MeasureSpec.AT_MOST ||
widthMode == MeasureSpec.UNSPECIFIED
)
) {
width -= (width - height * aspectRatio);
}
if( width / height < aspectRatio //too tall
&& (
heightMode == MeasureSpec.AT_MOST ||
heightMode == MeasureSpec.UNSPECIFIED
)
) {
height -= (height - width / aspectRatio);
}
setMeasuredDimension((int)width, (int)height);
}
The intention is, where possible, to create a rectangle whose aspect ratio is the same as the one specified by nominalheight and nominalwidth. Obviously if the function is passed MeasureSpec.EXACTLY then it should lay out with the dimension given in that direction.
I'm laying this View out with WRAP_CONTENT in the xml in both directions. What's puzzling me is that, stepping through the onMeasure calls, half of them show MeasureSpec.AT_MOST and the routine calculates the correct rectangle, and the other half show MeasureSpec.EXACTLY and it obviously uses the given dimensions. Even more puzzlingly, if I disable the conditionality (I would assume, from documentation and the example code, incorrectly) it works fine.
Why am I getting these alternating calls with different values, and how can I persuade Android to lay my View out in the correct dimensions?

Make children of HorizontalScrollView as big as the screen?

The way I solved this problem is by creating a custom view for the child views, and then overriding onMeasure() for the custom view. The new onMeasure() sets the width and height to be as large as possible.
The problem is when you show the soft keyboard and rotate the phone. With the orientation change and the keyboard showing, onMeasure() sets the "largest" available height to be something ridiculously small, so when I hide the keyboard, the child views have the wrong size.
Is there a way to tell the views to recompute the layout when the keyboard goes away? Or am I doing onMeasure() wrong? Here's the code:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(measureWidth(widthMeasureSpec),
measureHeight(heightMeasureSpec));
setLayoutParams(new LinearLayout.LayoutParams(
measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec))
);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public int measureWidth(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
Display display = ( (WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
int screenWidth = display.getWidth();
if (specMode == MeasureSpec.EXACTLY) {
// We were told how big to be
result = specSize;
} else {
// Measure the view
result = screenWidth;
if (specMode == MeasureSpec.AT_MOST) {
// Respect AT_MOST value if that was what is called for by measureSpec
result = Math.min(result, specSize);
}
}
Log.d(TAG, "Width: "+String.valueOf(result));
return result;
}
measureHeight() is done the same way.
Your super.onMeasure(widthMeasureSpec, heightMeasureSpec) uses the passed in values I would think you would want these to be the actual measured width and height:
super.onMeasure(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));

Categories

Resources