S.Drumble1
S.Drumble1

Reputation: 83

Setting suggested width and height to a custom view in android

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

Answers (2)

Mel
Mel

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

  1. width and height mode
  2. width and height size

Mode 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

GianhTran
GianhTran

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

Related Questions