You can get your custom view's measurements in onSizeChanged
.
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// use the provided width and height for whatever you need
}
Explanation
When a view is created, this is the order in which the following methods are called:
- Constructor
CustomView(Context context)
(if created programmatically)
CustomView(Context context, AttributeSet attrs)
(if created from xml)
onFinishInflate
(assuming you used the xml constructor)
onAttachedToWindow
onMeasure
onSizeChanged
onLayout
onDraw
The earliest you can get the view's measurements is in onMeasure
. Before that the width and height are 0
. However, the only thing you should be doing in onMeasure
is determining the size of the view. This method gets called several times while the view is telling the parent how big it wants to be but the parent is determining the actual final size. (See this answer for how onMeasure
is meant to be used.)
If you want to actually use the measured size for anything, the earliest place to do that is in onSizeChanged
. It gets called whenever the view is created because the size is changing from 0
to whatever the size is.
You could also use onLayout
, though as I understand it, onLayout
is for customizing how any children of your custom view are laid out. It also might get called more often than onSizeChanged
, for example, if you call requestLayout()
when the size hasn't actually changed.
You can also access the size in onDraw
with getMeasuredWidth()
and getMeasuredHeight()
. However, if you are using them to do any heavy calculations, it is better to do that beforehand. Generally speaking, try to keep as much out of onDraw
as possible since it may be called multiple times. (It gets called whenever invalidate()
gets called.)
See for yourself
If you don't believe me, you can see the order of events as they are called in the custom view below. Here is the output:
XML constructor called, measured size: (0, 0)
onFinishInflate called, measured size: (0, 0)
onAttachedToWindow called, measured size: (0, 0)
onMeasure called, measured size: (350, 1859)
onMeasure called, measured size: (350, 350)
onMeasure called, measured size: (350, 2112)
onMeasure called, measured size: (350, 350)
onSizeChanged called, measured size: (350, 350)
onLayout called, measured size: (350, 350)
onDraw called, measured size: (350, 350)
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.viewlifecycle.CustomView
android:id="@+id/customView"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="@color/colorAccent"/>
</RelativeLayout>
CustomView.java
public class CustomView extends View {
private void printLogInfo(String methodName) {
Log.i("TAG", methodName + " called, measured size: (" + getMeasuredWidth() + ", " + getMeasuredHeight() + ")");
}
// constructors
public CustomView(Context context) {
super(context);
printLogInfo("Programmatic constructor");
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
printLogInfo("XML constructor");
}
// lifecycle methods
@Override
protected void onFinishInflate() {
super.onFinishInflate();
printLogInfo("onFinishInflate");
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
printLogInfo("onAttachedToWindow");
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
printLogInfo("onMeasure");
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
printLogInfo("onSizeChanged");
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
printLogInfo("onLayout");
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
printLogInfo("onDraw");
}
}
Further reading