Android: No puedo tener ViewPager WRAP_CONTENT

He configurado un ViewPager simple que tiene un ImageView con una altura de 200dp en cada página.

Aquí está mi buscapersonas:

pager = new ViewPager(this); pager.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT)); pager.setBackgroundColor(Color.WHITE); pager.setOnPageChangeListener(listener); layout.addView(pager); 

A pesar de la altura establecida como wrap_content, el buscapersonas siempre llena la pantalla aunque la vista de la imagen sea sólo 200dp. Traté de reemplazar la altura del buscapersonas con "200", pero eso me da diferentes resultados con múltiples resoluciones. No puedo agregar "dp" a ese valor. ¿Cómo agrego 200dp al diseño del buscapersonas?

La modificación de la medida de su ViewPager siguiente manera le permitirá obtener la altura del niño más grande que tiene actualmente.

 @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; } heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } 

Otra solución más genérica es conseguir que wrap_content funcione.

He extendido ViewPager para anular onMeasure() . La altura se envuelve alrededor de la primera vista secundaria. Esto podría llevar a resultados inesperados si las vistas de los niños no son exactamente la misma altura. Para que la clase se puede ampliar fácilmente para decir animar el tamaño de la vista actual / página. Pero yo no necesitaba eso.

Puede usar este ViewPager en los diseños XML de yout igual que el ViewPager original:

 <view android:layout_width="match_parent" android:layout_height="wrap_content" class="de.cybergen.ui.layout.WrapContentHeightViewPager" android:id="@+id/wrapContentHeightViewPager" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true"/> 

Ventaja: Este enfoque permite usar ViewPager en cualquier diseño incluyendo RelativeLayout para superponer otros elementos ui.

Un inconveniente sigue siendo: Si desea utilizar márgenes, tiene que crear dos diseños anidados y dar a la interna los márgenes deseados.

Aquí está el código:

 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.getMeasuredHeight(); } if (specMode == MeasureSpec.AT_MOST) { result = Math.min(result, specSize); } } return result; } } 

Estaba respondiendo una pregunta muy similar sobre esto, y sucedió encontrar esto al buscar un acoplamiento para respaldar mis demandas, tan afortunado usted 🙂

Mi otra respuesta:
ViewPager no admite wrap_content ya que (normalmente) nunca tiene todos sus hijos cargados al mismo tiempo, y por lo tanto no puede obtener un tamaño adecuado (la opción sería tener un paginador que cambia de tamaño cada vez que cambió de página).

Sin embargo, puede establecer una dimensión precisa (por ejemplo, 150dp) y match_parent funciona también.
También puede modificar las dimensiones dinámicamente de su código cambiando el atributo height en su LayoutParams .

Para sus necesidades , puede crear ViewPager en su propio archivo xml, con el layout_height configurado en 200dp y luego en su código, en lugar de crear un nuevo ViewPager desde cero, puede inflar ese archivo xml:

 LayoutInflater inflater = context.getLayoutInflater(); inflater.inflate(R.layout.viewpagerxml, layout, true); 

Basé mi respuesta en Daniel López Lacalle y este post http://www.henning.ms/2013/09/09/viewpager-that-simply-dont-measure-up/ . El problema con la respuesta de Daniel es que en algunos casos mis hijos tenían una altura de cero. La solución fue desafortunadamente medir dos veces.

 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int mode = MeasureSpec.getMode(heightMeasureSpec); // Unspecified means that the ViewPager is in a ScrollView WRAP_CONTENT. // At Most means that the ViewPager is not in a ScrollView WRAP_CONTENT. if (mode == MeasureSpec.UNSPECIFIED || mode == MeasureSpec.AT_MOST) { // super has to be called in the beginning so the child views can be initialized. super.onMeasure(widthMeasureSpec, 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; } heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); } // super has to be called again so the new specs are treated as exact measurements super.onMeasure(widthMeasureSpec, heightMeasureSpec); } 

Esto también le permite establecer una altura en el ViewPager si lo desea o simplemente wrap_content.

Acabo de chocar con el mismo problema. Tenía un ViewPager y quería mostrar un anuncio en el botón de la misma. La solución que encontré fue conseguir que el buscapersonas en un RelativeView y establecer su layout_above a la identificación de la vista que quiero ver a continuación. Que funcionó para mí.

Aquí está mi diseño XML:

  <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <LinearLayout android:id="@+id/AdLayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:orientation="vertical" > </LinearLayout> <android.support.v4.view.ViewPager android:id="@+id/mainpager" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@+id/AdLayout" > </android.support.v4.view.ViewPager> </RelativeLayout> 

He enfrentado este problema en varios proyectos ya y nunca tuve una solución completa. Así que creé un proyecto WrapContentViewPager github como un reemplazo in situ para ViewPager.

https://github.com/rnevet/WCViewPager

La solución se inspiró en algunas de las respuestas aquí, pero mejora:

  • Cambia dinámicamente la altura de ViewPager de acuerdo con la vista actual, incluyendo el desplazamiento.
  • Toma en consideración la altura de las vistas de "decoración" como PagerTabStrip.
  • Toma en consideración todo el relleno.

Actualizado para la versión 24 de la biblioteca de soporte que rompió la implementación anterior.

Otra solución es actualizar la altura de ViewPager acuerdo con la altura de la página actual en su PagerAdapter . Asumiendo que estás creando tus páginas ViewPager esta manera:

 @Override public Object instantiateItem(ViewGroup container, int position) { PageInfo item = mPages.get(position); item.mImageView = new CustomImageView(container.getContext()); item.mImageView.setImageDrawable(item.mDrawable); container.addView(item.mImageView, 0); return item; } 

Donde mPages es una lista interna de PageInfo estructuras de PageInfo añadidas dinámicamente al PagerAdapter y CustomImageView es un método ImageView con overriden onMeasure() que establece su altura según el ancho especificado y mantiene la relación de aspecto de la imagen.

Puede forzar la altura de setPrimaryItem() en el método setPrimaryItem() :

 @Override public void setPrimaryItem(ViewGroup container, int position, Object object) { super.setPrimaryItem(container, position, object); PageInfo item = (PageInfo) object; ViewPager pager = (ViewPager) container; int width = item.mImageView.getMeasuredWidth(); int height = item.mImageView.getMeasuredHeight(); pager.setLayoutParams(new FrameLayout.LayoutParams(width, Math.max(height, 1))); } 

Observe el Math.max(height, 1) . Esto corrige un fallo molesto que ViewPager no actualiza la página mostrada (muestra en blanco), cuando la página anterior tiene cero altura (es decir, nula CustomImageView en el CustomImageView ), cada extraño deslizar hacia delante y hacia atrás entre dos páginas.

También me encontré con este problema, pero en mi caso tenía un FragmentPagerAdapter que estaba suministrando el ViewPager con sus páginas. El problema que tenía era que onMeasure() del ViewPager fue llamado antes de que se ViewPager cualquiera de los Fragments (y por lo tanto no podría dimensionarse correctamente).

Después de un poco de prueba y error, encontré que el método finishUpdate() del FragmentPagerAdapter se llama después de que los Fragments se hayan inicializado (de instantiateItem() en el FragmentPagerAdapter ), y también después / durante el desplazamiento de la página. Hice una pequeña interfaz:

 public interface AdapterFinishUpdateCallbacks { void onFinishUpdate(); } 

Que paso en mi FragmentPagerAdapter y llamo:

 @Override public void finishUpdate(ViewGroup container) { super.finishUpdate(container); if (this.listener != null) { this.listener.onFinishUpdate(); } } 

Que a su vez me permite llamar a setVariableHeight() en mi implementación de CustomViewPager :

 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; } } 

No estoy seguro de que es el mejor enfoque, me encantaría comentarios si usted piensa que es bueno / malo / mal, pero parece estar funcionando bastante bien en mi aplicación 🙂

Espero que esto ayude a alguien por ahí!

EDIT: Olvidé agregar un requestLayout() después de llamar a super.measure() (de lo contrario, no super.measure() dibujar la vista).

También olvidé agregar el relleno del padre a la altura final.

También cayó manteniendo la anchura / altura original MeasureSpecs en favor de crear uno nuevo como requerido. Han actualizado el código en consecuencia.

Otro problema que tuve fue que no se dimensionaría correctamente en un ScrollView y encontró que el culpable estaba midiendo al niño con MeasureSpec.EXACTLY lugar de MeasureSpec.UNSPECIFIED . Actualizado para reflejar esto.

Todos estos cambios se han agregado al código. Puede consultar el historial para ver las versiones antiguas (incorrectas) si lo desea.

Cuando se utiliza contenido estático dentro del viewpager y no se desea ninguna animación de fantasía, puede utilizar el siguiente paginador de vista

 public class HeightWrappingViewPager extends ViewPager { public HeightWrappingViewPager(Context context) { super(context); } public HeightWrappingViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); View firstChild = getChildAt(0); firstChild.measure(widthMeasureSpec, heightMeasureSpec); super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(firstChild.getMeasuredHeight(), MeasureSpec.EXACTLY)); } } 

Me topé con el mismo problema, y ​​también tuve que hacer que el ViewPager envolver su contenido cuando el usuario se desplaza entre las páginas. Utilizando la respuesta anterior de cybergen, definí el método onMeasure de la siguiente manera:

 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (getCurrentItem() < getChildCount()) { View child = getChildAt(getCurrentItem()); if (child.getVisibility() != GONE) { heightMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.UNSPECIFIED); child.measure(widthMeasureSpec, heightMeasureSpec); } setMeasuredDimension(getMeasuredWidth(), measureHeight(heightMeasureSpec, getChildAt(getCurrentItem()))); } } 

De esta manera, el método onMeasure fija la altura de la página actual mostrada por ViewPager.

 public CustomPager (Context context) { super(context); } public CustomPager (Context context, AttributeSet attrs) { super(context, attrs); } int getMeasureExactly(View child, int widthMeasureSpec) { child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); int height = child.getMeasuredHeight(); return MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); } @Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); boolean wrapHeight = MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST; final View tab = getChildAt(0); if (tab == null) { return; } int width = getMeasuredWidth(); if (wrapHeight) { // Keep the current measured width. widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY); } Fragment fragment = ((Fragment) getAdapter().instantiateItem(this, getCurrentItem())); heightMeasureSpec = getMeasureExactly(fragment.getView(), widthMeasureSpec); //Log.i(Constants.TAG, "item :" + getCurrentItem() + "|height" + heightMeasureSpec); // super has to be called again so the new specs are treated as // exact measurements. super.onMeasure(widthMeasureSpec, heightMeasureSpec); } 

Nada de lo sugerido arriba funcionó para mí. Mi caso de uso es tener 4 ViewPagers personalizados en ScrollView . La parte superior de ellos se mide en función de la relación de aspecto y el resto sólo tiene layout_height=wrap_content . He intentado cybergen , Daniel López soluciones Lacalle . Ninguno de ellos funciona completamente para mí.

Mi conjetura porqué cybergen no trabaja en la página> 1 es porque calcula la altura del buscapersonas basó en la página 1, que se oculta si usted rueda más lejos.

Las sugerencias de cybergen y Daniel López Lacalle tienen un comportamiento extraño en mi caso: 2 de 3 se cargan bien y 1 al azar la altura es 0. Aparece que onMeasure fue llamado antes de que los niños estuvieran poblados. Así que vine con una mezcla de estas dos respuestas + mis propias soluciones:

 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT) { // 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); int h = view.getMeasuredHeight(); setMeasuredDimension(getMeasuredWidth(), h); //do not recalculate height anymore getLayoutParams().height = h; } } } 

La idea es dejar ViewPager calcular las dimensiones de los niños y guardar la altura calculada de la primera página en los parámetros de diseño del ViewPager . No te olvides de establecer la altura del diseño del fragmento a wrap_content contrario puedes obtener height = 0. He utilizado este:

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content"> <!-- Childs are populated in fragment --> </LinearLayout> 

Tenga en cuenta que esta solución funciona muy bien si todas sus páginas tienen la misma altura . De lo contrario, deberá volver a calcular la altura de ViewPager según el niño activo actual. No lo necesito, pero si usted sugiere la solución estaría encantado de actualizar la respuesta.

Desde tiempo de palomitas de maíz código fuente de la aplicación Android encontré esta solución que ajusta dinámicamente el tamaño de viewpager con animación agradable en función del tamaño del niño actual.

.

 public class WrappingViewPager extends ViewPager { private Boolean mAnimStarted = false; public WrappingViewPager(Context context) { super(context); } public WrappingViewPager(Context context, AttributeSet attrs){ super(context, attrs); } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if(!mAnimStarted && null != getAdapter()) { int height = 0; View child = ((FragmentPagerAdapter) getAdapter()).getItem(getCurrentItem()).getView(); if (child != null) { child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); height = child.getMeasuredHeight(); if (VersionUtils.isJellyBean() && height < getMinimumHeight()) { height = getMinimumHeight(); } } // Not the best place to put this animation, but it works pretty good. int newHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); if (getLayoutParams().height != 0 && heightMeasureSpec != newHeight) { final int targetHeight = height; final int currentHeight = getLayoutParams().height; final int heightChange = targetHeight - currentHeight; Animation a = new Animation() { @Override protected void applyTransformation(float interpolatedTime, Transformation t) { if (interpolatedTime >= 1) { getLayoutParams().height = targetHeight; } else { int stepHeight = (int) (heightChange * interpolatedTime); getLayoutParams().height = currentHeight + stepHeight; } requestLayout(); } @Override public boolean willChangeBounds() { return true; } }; a.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { mAnimStarted = true; } @Override public void onAnimationEnd(Animation animation) { mAnimStarted = false; } @Override public void onAnimationRepeat(Animation animation) { } }); a.setDuration(1000); startAnimation(a); mAnimStarted = true; } else { heightMeasureSpec = newHeight; } } super.onMeasure(widthMeasureSpec, heightMeasureSpec); } } 

Si el ViewPager que está utilizando es un hijo de ScrollView Y tiene un hijo PagerTitleStrip , necesitará una ligera modificación de las grandes respuestas ya proporcionadas. Para referencia mi XML se parece a esto:

 <ScrollView android:id="@+id/match_scroll_view" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@color/white"> <LinearLayout android:id="@+id/match_and_graphs_wrapper" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <view android:id="@+id/pager" class="com.printandpixel.lolhistory.util.WrapContentHeightViewPager" android:layout_width="match_parent" android:layout_height="wrap_content"> <android.support.v4.view.PagerTitleStrip android:id="@+id/pager_title_strip" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top" android:background="#33b5e5" android:paddingBottom="4dp" android:paddingTop="4dp" android:textColor="#fff" /> </view> </LinearLayout> </ScrollView> 

En su onMeasure usted tiene que AGREGAR el PagerTitleStrip del PagerTitleStrip si uno se encuentra. De lo contrario su altura no se considerará en la altura más grande de todos los niños a pesar de que ocupa espacio adicional.

Espero que esto ayude a alguien más. Lo siento, es un poco un hack …

 public class WrapContentHeightViewPager extends ViewPager { public WrapContentHeightViewPager(Context context) { super(context); } public WrapContentHeightViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int pagerTitleStripHeight = 0; 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) { // get the measuredHeight of the tallest fragment height = h; } if (child.getClass() == PagerTitleStrip.class) { // store the measured height of the pagerTitleStrip if one is found. This will only // happen if you have a android.support.v4.view.PagerTitleStrip as a direct child // of this class in your XML. pagerTitleStripHeight = h; } } heightMeasureSpec = MeasureSpec.makeMeasureSpec(height+pagerTitleStripHeight, MeasureSpec.EXACTLY); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } } 

Para las personas que tienen este problema y la codificación de Xamarin Android en C #, esto también podría ser una solución rápida:

 pager.ChildViewAdded += (sender, e) => { e.Child.Measure ((int)MeasureSpecMode.Unspecified, (int)MeasureSpecMode.Unspecified); e.Parent.LayoutParameters.Height = e.Child.MeasuredHeight; }; 

Esto es útil principalmente si las vistas de su hijo son de la misma altura. De lo contrario, se le exigirá que almacene algún tipo de valor "minimumHeight" sobre todos los niños que comprueba, e incluso entonces puede que no quiera tener espacios vacíos visibles debajo de sus vistas menores.

La solución en sí no es suficiente para mí, sin embargo, pero eso es porque mis hijos son los elementos listViews y su MeasuredHeight no se calcula correctamente, parece.

Tengo una versión de WrapContentHeightViewPager que funcionaba correctamente antes de la API 23 que cambiará de tamaño la altura de la vista principal de la vista secundaria actual seleccionada.

Después de actualizar a API 23, dejó de funcionar. Resulta que la antigua solución estaba utilizando getChildAt(getCurrentItem()) para obtener la vista de niño actual para medir que no está funcionando. Consulte la solución aquí: https://stackoverflow.com/a/16512217/1265583

A continuación funciona con API 23:

 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int height = 0; ViewPagerAdapter adapter = (ViewPagerAdapter)getAdapter(); View child = adapter.getItem(getCurrentItem()).getView(); if(child != null) { child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); height = child.getMeasuredHeight(); } heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } 

Tengo un escenario similar (pero más complejo). Tengo un diálogo, que contiene un ViewPager.
Una de las páginas secundarias es corta, con una altura estática.
Otra página secundaria siempre debe ser lo más alta posible.
Otra página secundaria contiene un ScrollView, y la página (y por lo tanto todo el cuadro de diálogo) debe WRAP_CONTENT si el contenido ScrollView no necesita la altura completa disponible para el diálogo.

Ninguna de las respuestas existentes funcionó completamente para este escenario específico. Espera, es un viaje lleno de baches.

 void setupView() { final ViewPager.SimpleOnPageChangeListener pageChangeListener = new ViewPager.SimpleOnPageChangeListener() { @Override public void onPageSelected(int position) { currentPagePosition = position; // Update the viewPager height for the current view /* Borrowed from https://github.com/rnevet/WCViewPager/blob/master/wcviewpager/src/main/java/nevet/me/wcviewpager/WrapContentViewPager.java Gather the height of the "decor" views, since this height isn't included when measuring each page's view height. */ int decorHeight = 0; for (int i = 0; i < viewPager.getChildCount(); i++) { View child = viewPager.getChildAt(i); ViewPager.LayoutParams lp = (ViewPager.LayoutParams) child.getLayoutParams(); if (lp != null && lp.isDecor) { int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK; boolean consumeVertical = vgrav == Gravity.TOP || vgrav == Gravity.BOTTOM; if (consumeVertical) { decorHeight += child.getMeasuredHeight(); } } } int newHeight = decorHeight; switch (position) { case PAGE_WITH_SHORT_AND_STATIC_CONTENT: newHeight += measureViewHeight(thePageView1); break; case PAGE_TO_FILL_PARENT: newHeight = ViewGroup.LayoutParams.MATCH_PARENT; break; case PAGE_TO_WRAP_CONTENT: // newHeight = ViewGroup.LayoutParams.WRAP_CONTENT; // Works same as MATCH_PARENT because...reasons... // newHeight += measureViewHeight(thePageView2); // Doesn't allow scrolling when sideways and height is clipped /* Only option that allows the ScrollView content to scroll fully. Just doing this might be way too tall, especially on tablets. (Will shrink it down below) */ newHeight = ViewGroup.LayoutParams.MATCH_PARENT; break; } // Update the height ViewGroup.LayoutParams layoutParams = viewPager.getLayoutParams(); layoutParams.height = newHeight; viewPager.setLayoutParams(layoutParams); if (position == PAGE_TO_WRAP_CONTENT) { // This page should wrap content // Measure height of the scrollview child View scrollViewChild = ...; // (generally this is a LinearLayout) int scrollViewChildHeight = scrollViewChild.getHeight(); // full height (even portion which can't be shown) // ^ doesn't need measureViewHeight() because... reasons... if (viewPager.getHeight() > scrollViewChildHeight) { // View pager too tall? // Wrap view pager height down to child height newHeight = scrollViewChildHeight + decorHeight; ViewGroup.LayoutParams layoutParams2 = viewPager.getLayoutParams(); layoutParams2.height = newHeight; viewPager.setLayoutParams(layoutParams2); } } // Bonus goodies :) // Show or hide the keyboard as appropriate. (Some pages have EditTexts, some don't) switch (position) { // This case takes a little bit more aggressive code than usual if (position needs keyboard shown){ showKeyboardForEditText(); } else if { hideKeyboard(); } } } }; viewPager.addOnPageChangeListener(pageChangeListener); viewPager.getViewTreeObserver().addOnGlobalLayoutListener( new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { // http://stackoverflow.com/a/4406090/4176104 // Do things which require the views to have their height populated here pageChangeListener.onPageSelected(currentPagePosition); // fix the height of the first page if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { viewPager.getViewTreeObserver().removeOnGlobalLayoutListener(this); } else { viewPager.getViewTreeObserver().removeGlobalOnLayoutListener(this); } } } ); } ... private void showKeyboardForEditText() { // Make the keyboard appear. getDialog().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN); inputViewToFocus.requestFocus(); // http://stackoverflow.com/a/5617130/4176104 InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); inputMethodManager.toggleSoftInputFromWindow( inputViewToFocus.getApplicationWindowToken(), InputMethodManager.SHOW_IMPLICIT, 0); } ... /** * Hide the keyboard - http://stackoverflow.com/a/8785471 */ private void hideKeyboard() { InputMethodManager inputManager = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); inputManager.hideSoftInputFromWindow(inputBibleBookStart.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); } ... //https://github.com/rnevet/WCViewPager/blob/master/wcviewpager/src/main/java/nevet/me/wcviewpager/WrapContentViewPager.java private int measureViewHeight(View view) { view.measure(ViewGroup.getChildMeasureSpec(-1, -1, view.getLayoutParams().width), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); return view.getMeasuredHeight(); } 

Much thanks to @Raanan for the code to measure views and measure the decor height. I ran into problems with his library- the animation stuttered, and I think my ScrollView wouldn't scroll when the height of the dialog was short enough to require it.

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.