I have setup a simple ViewPager that has an ImageView with a height of 200dp on each page.
Here is my pager:
pager = new ViewPager(this); pager.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT)); pager.setBackgroundColor(Color.WHITE); pager.setOnPageChangeListener(listener); layout.addView(pager);
Despite the height set as wrap_content, the pager always fills the screen even though the imageview is only 200dp. I tried to replace the height of the pager with "200" but that gives me different results with multiple resolutions. I am unable to add "dp" to that value. How do I add 200dp to the pager's layout?
Overriding onMeasure of your ViewPager
as follows will make it get the height of the biggest child it currently has.
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int height = 0; for(int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); int h = child.getMeasuredHeight(); if(h > height) height = h; } if (height != 0) { heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); } super.onMeasure(widthMeasureSpec, heightMeasureSpec); }
Another more generic solution is to get wrap_content
to just work.
I've extended ViewPager
to override onMeasure()
. The height is wraped around the first child view. This could lead to unexpected results if the child views are not exactly the same height. For that the class can be easily extended to let's say animate to the size of the current view/page. But I didn't need that.
You can use this ViewPager in yout XML layouts just like the original ViewPager:
Advantage: This approach allows using the ViewPager in any layout including RelativeLayout to overlay other ui elements.
One drawback remains: If you want to use margins, you have to create two nested layouts and give the inner one the desired margins.
Here's the code:
public class WrapContentHeightViewPager extends ViewPager { /** * Constructor * * @param context the context */ public WrapContentHeightViewPager(Context context) { super(context); } /** * Constructor * * @param context the context * @param attrs the attribute set */ public WrapContentHeightViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); // find the first child view View view = getChildAt(0); if (view != null) { // measure the first child view with the specified measure spec view.measure(widthMeasureSpec, heightMeasureSpec); } setMeasuredDimension(getMeasuredWidth(), measureHeight(heightMeasureSpec, view)); } /** * Determines the height of this view * * @param measureSpec A measureSpec packed into an int * @param view the base view with already measured height * * @return The height of the view, honoring constraints from measureSpec */ private int measureHeight(int measureSpec, View view) { int result = 0; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); if (specMode == MeasureSpec.EXACTLY) { result = specSize; } else { // set the height from the base view if available if (view != null) { result = view.