Reputation: 83
I'm learning how to create custom views in android. Currently I don't understand how to set minimum width and height of it. Why do I think that it is not set? Because I print value of getSuggestedMinimumWidth()
which returns a 0 to me.
In the view there are some figures drown on the canvas meaning there are no views under it in the hierarchy unless views are added automatically(are they btw?).
I tried googling possible ways of setting minimum width or height to a custom view but didn't find anything.
So, how do I set minimum width and height to a custom view in onMeasure()
method? If there are some question like why would you need to override the method then the answer is that I want to learn how to work with it.
Upvotes: 1
Views: 2012
Reputation: 1820
Measuring a custom view is actually easier than it looks. You should take a look at MeasureSpec.
You generally need to handle cases where your view can be given a specific size, wrap_content
or match_parent
.
When onMeasure
is called, it's given widthMeasureSpec
and heightMeasureSpec
parameters, which you can use in combination with MeasureSpec
to get
width
and height
modewidth
and height
sizeMode can be one of three pre-defined values in MeasureSpec
:
UNSPECIFIED
The parent has not imposed any constraint on the child. It can be whatever size it wants.
EXACTLY
The parent has determined an exact size for the child. The child is going to be given those bounds regardless of how big it wants to be.
AT_MOST
The child can be as large as it wants up to the specified size.
What you need to do is to cover these cases, which ~mostly~ looks like this:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
if (widthMode == MeasureSpec.EXACTLY) {
width = //Calculation
} else if (widthMode == MeasureSpec.AT_MOST) {
width = //Calculation
} else {
// UNSPECIFIED
width = //Calculation
}
if (heightMode == MeasureSpec.EXACTLY) {
height = //Calculation
} else if (heightMode == MeasureSpec.AT_MOST) {
height = //Calculation
} else {
// UNSPECIFIED
height = //Calculation
}
setMeasuredDimension(width, height);
}
There is also case where you should measure child views if your custom view is a ViewGroup
and can contain 1 or many child views. This is a piece of code I wrote couple years ago for measuring a custom ViewGroup
which can have 1 child ( mChild
) at most and needs to calculate its height / width properties by also thinking it'll draw a stroke ( mStrokeWidth
) around the child.
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
measureChild(mChild, widthMeasureSpec, heightMeasureSpec);
int childWidth = mChild.getMeasuredWidth();
int childHeight = mChild.getMeasuredHeight();
if (widthMode == MeasureSpec.EXACTLY) {
width = MeasureSpec.getSize(widthMeasureSpec);
} else if (widthMode == MeasureSpec.AT_MOST) {
width = Math.min(width, (int) (childWidth + (mStrokeWidth * 2)));
}
if (heightMode == MeasureSpec.EXACTLY) {
height = MeasureSpec.getSize(heightMeasureSpec);
} else if (heightMode == MeasureSpec.AT_MOST) {
height = Math.min(height, (int) (childHeight + (mStrokeWidth * 2)));
}
setMeasuredDimension(width, height);
}
Upvotes: 1
Reputation: 3711
My solution is very easy, hope it will helps
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthSize < MIN_WIDTH) {
widthSize = MIN_WIDTH;
}
if (heightSize < MIN_HEIGHT) {
heightSize = MIN_HEIGHT;
}
setMeasuredDimension(widthSize , heightSize );
}
Upvotes: 1