Intereting Posts
Можно ли пропускать onMeasure при добавлении представления в ViewGroup? Как установить текст диалога google api в языке по умолчанию приложения Отправлять намерение от службы к деятельности Как запустить настройки непосредственно на странице «Беспроводные сети»? Android bulkTransfer возвращает -1 при чтении данных, но в буфере действительно есть некоторые данные Сократить библиотеку сервисов Google Play для использования только с Google Analytics Могу ли я отображать конструкцию дизайна Snackbar в диалоговом окне? Получение черного ImageView с использованием Picasso и Glide Контактная информация для Android: как получить обратную ссылку (Google) из Интернета (и, таким образом, «отменить» прежнее локальное изменение изображения) Невозможно нарисовать холст HTML5 с помощью Phonegap 2.7 Разрешение предоставляется только системному приложению, в манифесте Каков наилучший способ объединить (объединить) 2 JSONObjects? Вызов метода перехвата Android отправляет изображение на сервер через MultipartEntity – настройка Content-type? FragmentManager.getFragmens (). Size () не уменьшается после FragmentTransaction.remove (фрагмент)

Android: я не могу иметь ViewPager WRAP_CONTENT

Я установил простой ViewPager, который имеет ImageView с высотой 200dp на каждой странице.

Вот мой пейджер:

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

Несмотря на высоту, установленную как wrap_content, пейджер всегда заполняет экран, хотя изображение имеет только 200 дп. Я попытался заменить высоту пейджера «200», но это дает мне разные результаты с несколькими разрешениями. Я не могу добавить «dp» к этому значению. Как добавить 200dp в макет пейджера?

Solutions Collecting From Web of "Android: я не могу иметь ViewPager WRAP_CONTENT"

Переопределение onMeasure вашего ViewPager как ViewPager ниже, позволит получить высоту самого большого в настоящее время ребенка.

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

Еще одно общее решение – заставить wrap_content работать.

Я расширил ViewPager чтобы переопределить onMeasure() . Высота разворачивается вокруг первого детского вида. Это может привести к непредвиденным результатам, если представления для детей не соответствуют одинаковой высоте. Для этого класс можно легко расширить, чтобы, скажем, оживить размер текущего вида / страницы. Но мне это не нужно.

Вы можете использовать этот ViewPager в XML-макетах yout так же, как оригинальный ViewPager:

 <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"/> 

Преимущество: этот подход позволяет использовать ViewPager в любом макете, включая RelativeLayout, для наложения других элементов ui.

Остается один недостаток: если вы хотите использовать поля, вам нужно создать два вложенных макета и дать внутреннему желаемые поля.

Вот код:

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

Я просто отвечал на очень похожий вопрос об этом, и мне удалось найти это, когда искали ссылку, чтобы поддержать мои претензии, так что вам повезло 🙂

Мой другой ответ:
ViewPager не поддерживает wrap_content поскольку он (обычно) никогда не загружает все свои дети одновременно и поэтому не может получить соответствующий размер (опция должна заключаться в том, чтобы пейджер менял размер каждый раз, когда вы переключали страницу).

Однако вы можете установить точное измерение (например, 150dp) и match_parent .
Вы также можете динамически изменять размеры из своего кода, изменяя LayoutParams height в его LayoutParams .

Для ваших нужд вы можете создать ViewPager в собственном xml-файле, а layout_height, установленный в 200dp, а затем в вашем коде вместо создания нового ViewPager с нуля, вы можете раздуть этот XML-файл:

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

Я основал свой ответ на Daniel López Lacalle и этот пост http://www.henning.ms/2013/09/09/viewpager-that-simply-dont-measure-up/ . Проблема с ответом Даниэля в том, что в некоторых случаях у моих детей была высота нуля. Решение было, к сожалению, дважды.

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

Это также позволяет вам устанавливать высоту на ViewPager, если вы так хотите или просто wrap_content.

Я просто столкнулся с тем же вопросом. У меня был ViewPager, и я хотел показать объявление на кнопке. Решение, которое я нашел, – это получить пейджер в RelativeView и установить его layout_above для идентификатора вида, который я хочу увидеть ниже. Это сработало для меня.

Вот мой макет 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> 

Я уже сталкивался с этой проблемой в нескольких проектах и ​​никогда не имел полного решения. Поэтому я создал проект gigub WrapContentViewPager в качестве замены на месте для ViewPager.

https://github.com/rnevet/WCViewPager

Решение было вдохновлено некоторыми ответами здесь, но улучшается:

  • Динамически изменяет высоту ViewPager в соответствии с текущим представлением, включая прокрутку.
  • Принимает во внимание высоту «декора», например PagerTabStrip.
  • Принимает во внимание все простыни.

Обновлено для версии 24 библиотеки поддержки, которая нарушила предыдущую реализацию.

Другим решением является обновление высоты ViewPager соответствии с текущей высотой страницы в PagerAdapter . Предполагая, что вы создаете страницы ViewPager таким образом:

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

Где mPages – это внутренний список структур PageInfo динамически добавленных в PagerAdapter а CustomImageView – это просто обычный ImageView с переопределением onMeasure() который устанавливает его высоту в соответствии с указанной шириной и сохраняет пропорции изображения.

Вы можете заставить высоту setPrimaryItem() в 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))); } 

Обратите внимание на Math.max(height, 1) . Это устраняет раздражающую ошибку, которую ViewPager не обновляет отображаемую страницу (показывает ее пустым), когда предыдущая страница имеет нулевую высоту (т. CustomImageView в CustomImageView ), каждая нечетная прокрутка вперед и назад между двумя страницами.

Я также столкнулся с этой проблемой, но в моем случае у меня был FragmentPagerAdapter который снабжал ViewPager своими страницами. Проблема была в том, что onMeasure() ViewPager был вызван до того, как был создан какой-либо из Fragments (и, следовательно, не мог корректно определить размер).

После нескольких проб и ошибок я обнаружил, что метод finishUpdate() для FragmentPagerAdapter вызывается после инициализации Fragments (из instantiateItem() в FragmentPagerAdapter ), а также после / во время прокрутки страницы. Я сделал небольшой интерфейс:

 public interface AdapterFinishUpdateCallbacks { void onFinishUpdate(); } 

Который я перехожу в свой FragmentPagerAdapter и звоню:

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

setVariableHeight() в свою очередь, позволяет мне вызвать setVariableHeight() в моей реализации 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; } } 

Я не уверен, что это лучший подход, мне бы понравились комментарии, если вы считаете, что это хорошо / плохо / злобно, но, похоже, он работает очень хорошо в моей реализации 🙂

Надеюсь, это поможет кому-то!

EDIT: я забыл добавить requestLayout() после вызова super.measure() (иначе он не перерисовывает представление).

Я также забыл добавить дополнение родителя к конечной высоте.

Я также отказался от первоначальной ширины / высоты MeasureSpecs в пользу создания нового по мере необходимости. Обновите код соответствующим образом.

Еще одна проблема, с которой я столкнулся, заключалась в том, что она не будет правильно ScrollView размер в ScrollView и обнаружила, что виновник ScrollView с помощью MeasureSpec.EXACTLY вместо MeasureSpec.UNSPECIFIED . Обновлено, чтобы отразить это.

Все эти изменения были добавлены в код. Вы можете проверить историю, чтобы увидеть старые (неправильные) версии, если хотите.

При использовании статического содержимого внутри viewpager и нежелательной анимации вы можете использовать следующий просмотр пейджера

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

Я столкнулся с той же проблемой, и мне также пришлось заставить ViewPager обходить его содержимое, когда пользователь прокручивал страницы. Используя приведенный выше ответ cybergen, я определил метод onMeasure следующим образом:

 @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()))); } } 

Таким образом, метод onMeasure устанавливает высоту текущей страницы, отображаемой 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); } 

Ничто из предложенного выше не работало для меня. В моем примере использования есть 4 пользовательских ViewPagers в ScrollView . Верхняя часть измеряется на основе соотношения сторон, а остальная часть имеет layout_height=wrap_content . Я пробовал киберген , решения Daniel López Lacalle . Никто из них не работает полностью для меня.

Я думаю, почему киберген не работает на странице> 1, потому что он вычисляет высоту пейджера на странице 1, которая скрыта, если вы прокручиваете дальше.

И киберген, и предложение Даниэля Лопеса Лакале имеют странное поведение в моем случае: 2 из 3 загружаются нормально, а 1 случайная высота равна 0. Появляется, что onMeasure до того, как были заселены дети. Поэтому я придумал смесь этих двух ответов + мои собственные исправления:

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

Идея заключается в том, чтобы позволить ViewPager рассчитать размеры детей и сохранить расчетную высоту первой страницы в параметрах макета ViewPager . Не забудьте установить высоту макета фрагмента в wrap_content иначе вы можете получить height = 0. Я использовал этот:

 <?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> 

Обратите внимание, что это решение отлично работает, если все ваши страницы имеют одинаковую высоту . В противном случае вам необходимо пересчитать высоту ViewPager на основе текущего дочернего активного ViewPager . Мне это не нужно, но если вы предложите решение, я был бы рад обновить ответ.

Исходный код приложения для Android от Popcorn. Я нашел это решение, которое динамически регулирует размер viewpager с хорошей анимацией в зависимости от размера текущего ребенка.

https://git.popcorntime.io/popcorntime/android/blob/5934f8d0c8fed39af213af4512272d12d2efb6a6/mobile/src/main/java/pct/droid/widget/WrappingViewPager.java

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

Если ViewPager который вы используете, является дочерним элементом ScrollView и имеет PagerTitleStrip элемент PagerTitleStrip вам нужно будет использовать небольшую модификацию отличных ответов, уже предоставленных. Для справки мой XML выглядит следующим образом:

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

В вашем onMeasure вы должны ДОБАВИТЬ измеренный PagerTitleStrip если он найден. В противном случае его высота не будет учитываться на самой большой высоте всех детей, даже если она занимает дополнительное пространство.

Надеюсь, это поможет кому-то другому. Извините, что это немного взломать …

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

Для людей, имеющих эту проблему и кодирующих Xamarin Android на C #, это также может быть быстрым решением:

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

Это в основном полезно, если представления вашего ребенка имеют одинаковую высоту. В противном случае вам нужно будет хранить какое-то значение «minimumHeight» для всех детей, с которыми вы проверяете, и даже тогда вы, возможно, не захотите, чтобы пустые пространства были видны под вашими меньшими детскими представлениями.

Самим решением для меня пока недостаточно, но это потому, что мои дочерние элементы – listViews, и их MeasuredHeight вычисляется неправильно.

У меня есть версия WrapContentHeightViewPager, которая корректно работала до API 23, которая изменит размер базы высоты родительского представления на выбранное дочернее представление.

После перехода на API 23 он перестает работать. Оказывается, старое решение использовало getChildAt(getCurrentItem()) чтобы получить текущее дочернее представление для измерения, которое не работает. См. Решение здесь: https://stackoverflow.com/a/16512217/1265583

Ниже работает с 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); } 

У меня есть аналогичный (но более сложный сценарий). У меня есть диалог, содержащий ViewPager.
Одна из дочерних страниц коротка, со статической высотой.
Другая дочерняя страница всегда должна быть как можно выше.
Другая дочерняя страница содержит ScrollView, а страница (и, следовательно, весь диалог) должна WRAP_CONTENT, если содержимое ScrollView не нуждается в полной высоте, доступной для диалога.

Ни один из существующих ответов не работал полностью для этого конкретного сценария. Держись – это ухабистая поездка.

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

Огромное спасибо @Raanan за код для измерения просмотров и измерения высоты декора. Я столкнулся с проблемами с его библиотекой – анимация заикалась, и я думаю, что ScrollView не прокручивал бы, когда высота диалога была достаточно коротка, чтобы потребовать его.