I also ran into this problem, but in my case I had a FragmentPagerAdapter
that was supplying the ViewPager
with its pages. The problem I had was that onMeasure()
of the ViewPager
was called before any of the Fragments
had been created (and therefore could not size itself correctly).
After a bit of trial and error, I found that the finishUpdate()
method of the FragmentPagerAdapter is called after the Fragments
have been initialized (from instantiateItem()
in the FragmentPagerAdapter
), and also after/during the page scrolling. I made a small interface:
public interface AdapterFinishUpdateCallbacks
{
void onFinishUpdate();
}
which I pass into my FragmentPagerAdapter
and call:
@Override
public void finishUpdate(ViewGroup container)
{
super.finishUpdate(container);
if (this.listener != null)
{
this.listener.onFinishUpdate();
}
}
which in turn allows me to call setVariableHeight()
on my CustomViewPager
implementation:
public void setVariableHeight()
{
// super.measure() calls finishUpdate() in adapter, so need this to stop infinite loop
if (!this.isSettingHeight)
{
this.isSettingHeight = true;
int maxChildHeight = 0;
int widthMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY);
for (int i = 0; i < getChildCount(); i++)
{
View child = getChildAt(i);
child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(ViewGroup.LayoutParams.WRAP_CONTENT, MeasureSpec.UNSPECIFIED));
maxChildHeight = child.getMeasuredHeight() > maxChildHeight ? child.getMeasuredHeight() : maxChildHeight;
}
int height = maxChildHeight + getPaddingTop() + getPaddingBottom();
int heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
super.measure(widthMeasureSpec, heightMeasureSpec);
requestLayout();
this.isSettingHeight = false;
}
}
I am not sure it is the best approach, would love comments if you think it is good/bad/evil, but it seems to be working pretty well in my implementation :)
Hope this helps someone out there!
EDIT: I forgot to add a requestLayout()
after calling super.measure()
(otherwise it doesn't redraw the view).
I also forgot to add the parent's padding to the final height.
I also dropped keeping the original width/height MeasureSpecs in favor of creating a new one as required. Have updated the code accordingly.
Another problem I had was that it wouldn't size itself correctly in a ScrollView
and found the culprit was measuring the child with MeasureSpec.EXACTLY
instead of MeasureSpec.UNSPECIFIED
. Updated to reflect this.
These changes have all been added to the code. You can check the history to see the old (incorrect) versions if you want.