whatyouhide
whatyouhide

Reputation: 16781

View becomes smaller on every call to onMeasure() and onSizeChanged()

I have a custom view with just a circle inside it. I have a problem with its dimensions.

I overrode both onSizeChanged() and onMeasure(), but I'm afraid I'm missing something with onMeasure(). This view being substantially just a circle, I overrode getSuggestedMinimumHeight() and getSuggestedMinimumWidth() in order to make both of them return the radius of the circle. Now everything seemed to work fine until I decided to update some other components of the activity.

When I update the text of a TextView (or a Button) in the activity where my view is situated, my view becomes smaller (on every update) calling both onMeasure() and onSizeChanged().

Here is my onMeasure() method. My question is: why doesn't it behaves always the same?

@Override
protected int getSuggestedMinimumHeight() {
    return (int) (mCircleRadius + mCircleStrokeWidth/2);
}

@Override
protected int getSuggestedMinimumWidth() {
    return (int) (mCircleRadius + mCircleStrokeWidth/2);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Log.d("SIZES", "called onMeasure()");

    int minw = getPaddingLeft() + getPaddingRight() + getSuggestedMinimumWidth();

    int minh = getSuggestedMinimumHeight() + getPaddingBottom() + getPaddingTop();

    setMeasuredDimension(minw, minh);
}

Here's the XML for the layout:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="http://schemas.android.com/apk/res/com.nhasu"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <com.nhasu.ProgressCircleTimer
        android:id="@+id/progcircle_smallBreaks"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:padding="10dp"
        custom:circle_radius="300dp" />

    <Button
        android:id="@+id/btn" 
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:layout_centerInParent="true"

        android:onClick="onStartClicked"
        android:text="@string/btn_start"
        android:textSize="40sp" />
</RelativeLayout>

Note that I edit the text of the Button with a simple Button.setText().

Upvotes: 3

Views: 2524

Answers (1)

Streets Of Boston
Streets Of Boston

Reputation: 12596

You don't need the onSizeChanged to determine the size of your custom view. When the onSizeChanged is called, your custom view has been measured and laid-out.

Just implement the onMeasure appropriately:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    Log.d("SIZES", "called onMeasure()");

    int minw = getPaddingLeft() + getPaddingRight() + getSuggestedMinimumWidth();
    int minh = getSuggestedMinimumHeight() + getPaddingBottom() + getPaddingTop();

    setMeasuredDimension(
            resolveSize(minw, widthMeasureSpec),
            resolveSize(minh, heightMeasureSpec));
}

public static int resolveSize(int childSize, int measureSpec) {
    int specMode = MeasureSpec.getMode(measureSpec);
    int specSize = MeasureSpec.getSize(measureSpec);
    switch (specMode) {
    case MeasureSpec.UNSPECIFIED:
        // Just return the child's size.
        return childSize;

    case MeasureSpec.AT_MOST:
        // Return the smallest of childSize and specSize
        return (specSize < childSize)? specSize : childSize;

    case MeasureSpec.EXACTLY:
        // Should honor parent-View's request for the given size.
        // If not desired, don't set the child's layout_width/layout_height to a fixed
        // value (nor fill_parent in certain cases).
        return specSize;
    }

    return childSize;
}

I added the implementation of resolveSize to this answer so you can see what happens, but it is already implemented for you in View.resolveSize.

Upvotes: 3

Related Questions