Reputation: 16781
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
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