Android:我无法使用ViewPager WRAP_CONTENT
我已经设置了一个简单的ViewPager,每个页面上都有一个高度为200dp的ImageView。
这是我的传呼机:
pager = new ViewPager(this); pager.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT)); pager.setBackgroundColor(Color.WHITE); pager.setOnPageChangeListener(listener); layout.addView(pager);
尽pipe高度设置为wrap_content,但即使imageview仅为200dp,传呼机也将始终填满屏幕。 我试图用“200”replace传呼机的高度,但是这给了我不同的结果与多个决议。 我无法将“dp”添加到该值。 如何将200dp添加到寻呼机的布局?
如下所示重写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; } if (height != 0) { heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); } super.onMeasure(widthMeasureSpec, heightMeasureSpec); }
另一个更通用的解决scheme是让wrap_content
正常工作。
我已经扩展ViewPager
来覆盖onMeasure()
。 高度被包裹在第一个子视图周围。 这可能会导致意外的结果,如果子视图不完全相同的高度。 为了这个类可以很容易地扩展到让我们说animation的大小当前视图/页面。 但是我不需要那个。
您可以像原来的ViewPager一样,在您的XML布局中使用这个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"/>
优点:这种方法允许在包括RelativeLayout的任何布局中使用ViewPager来覆盖其他UI元素。
一个缺点仍然是:如果你想使用边距,你必须创build两个嵌套布局,并给内部一个理想的边距。
代码如下:
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; } }
我根据DanielLópezLacalle的回答和这个posthttp://www.henning.ms/2013/09/09/viewpager-that-simply-dont-measure-up/ 。 但以理回答的问题是在某些情况下,我的孩子有零高。 解决scheme不幸的是测量了两次。
@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。
我只是回答了一个非常类似的问题,碰巧find一个链接来支持我的说法,所以很幸运:)
我的其他答案:
ViewPager不支持wrap_content
因为它(通常)永远不会同时加载所有的孩子,因此可能无法获得合适的大小(选项可能是在每次切换页面时都有一个更改大小的传呼机)。
你可以设置一个精确的尺寸(例如150dp), match_parent
也可以。
您还可以通过更改LayoutParams
的height
属性来从代码中dynamic修改维度。
为了您的需要,您可以在自己的xml文件中创buildViewPager,并将layout_height设置为200dp,然后在您的代码中,而不是从头开始创build新的ViewPager,则可以对该xml文件进行充气:
LayoutInflater inflater = context.getLayoutInflater(); inflater.inflate(R.layout.viewpagerxml, layout, true);
我碰到了同样的问题。 我有一个ViewPager,我想在它的button上显示一个广告。 我find的解决scheme是让传呼机进入一个RelativeView,并将其layout_above设置为我想在下面看到的视图ID。 为我工作。
这里是我的布局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>
我已经在几个项目中遇到了这个问题,从来没有一个完整的解决scheme。 所以我创build了一个WrapContentViewPager github项目作为ViewPager的就地replace。
https://github.com/rnevet/WCViewPager
这个解决scheme的灵感来自于这里的一些答案,但在以下方面有所改进
- 包括在滚动时根据当前视图dynamic更改ViewPager高度。
- 考虑“装饰”视图的高度,如PagerTabStrip。
- 考虑所有填充。
支持库版本24的更新已经破坏了之前的实现。
我也遇到了这个问题,但在我的情况下,我有一个FragmentPagerAdapter
提供ViewPager
的页面。 我遇到的问题是ViewPager
onMeasure()
在创build任何Fragments
之前调用(因此无法正确调整自身大小)。
经过一些试验和错误之后,我发现FragmentPagerAdapter的finishUpdate()
方法在Fragments初始化之后(从FragmentPagerAdapter
中的instantiateItem()
开始调用,也在页面滚动之后/期间调用。 我做了一个小界面:
public interface AdapterFinishUpdateCallbacks { void onFinishUpdate(); }
我传入我的FragmentPagerAdapter
并调用:
@Override public void finishUpdate(ViewGroup container) { super.finishUpdate(container); if (this.listener != null) { this.listener.onFinishUpdate(); } }
这反过来又允许我在我的CustomViewPager
实现上调用setVariableHeight()
:
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; } }
我不确定这是否是最好的方法,如果你认为它是好的/坏的/邪恶的,会喜欢评论,但是在我的实现中它似乎工作得很好:)
希望这可以帮助那里的人!
编辑:我忘了添加一个requestLayout()
后调用super.measure()
(否则它不会重绘视图)。
我也忘了添加父母的填充到最后的高度。
我也下降保持原来的宽度/高度MeasureSpecs有利于根据需要创build一个新的。 已经相应地更新了代码。
我有的另一个问题是,它不会在ScrollView
正确的大小,发现罪魁祸首是用MeasureSpec.EXACTLY
而不是MeasureSpec.UNSPECIFIED
测量孩子。 更新以反映这一点。
这些更改已经全部添加到代码中。 如果需要,可以查看历史logging以查看旧(不正确)的版本。
另一个解决scheme是根据当前页面高度在PagerAdapter
更新ViewPager
高度。 假设您正在以这种方式创buildViewPager
页面:
@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
结构的内部列表,dynamic添加到PagerAdapter
和CustomImageView
只是常规的ImageView
带有重载onMeasure()
方法,根据指定的宽度设置其高度并保持图像宽高比。
您可以在setPrimaryItem()
方法中强制ViewPager
height:
@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
可绘制空值)时,在两个页面之间来回刷新的烦人错误。
当在viewpager中使用静态内容,并且不希望看到animation时,可以使用下面的视图寻呼机
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)); } }
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); }
我遇到了同样的问题,当用户在页面之间滚动时,我也不得不使用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显示的当前页面的高度。
上面没有任何build议为我工作。 我的用例是在ScrollView
有4个自定义的ViewPagers。 其中,顶部是根据宽高比进行测量,其余部分是layout_height=wrap_content
。 我已经试过cybergen , DanielLópezLacalle解决scheme。 他们都没有为我完全工作。
我的猜测为什么cybergen不能在页面> 1上工作是因为它计算页面1的高度,这是隐藏的,如果你进一步滚动。
cybergen和DanielLópezLacalle的build议在我的例子中有奇怪的行为:3中的2个是正确的,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
布局参数中第一页的计算高度。 不要忘了将fragment的布局高度设置为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>
请注意,如果您的所有页面具有相同的高度,则此解决scheme效果很好 。 否则,您需要根据当前的子活动重新计算ViewPager
高度。 我不需要它,但如果你build议解决scheme,我会很乐意更新答案。
从爆米花时间android应用程序的源代码我发现这个解决scheme,根据当前的孩子的大小dynamic调整viewpager的大小与animation很好。
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
子项,那么您需要对已经提供的优秀答案进行一些修改。 为了参考我的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
中,如果find,则必须添加 PagerTitleStrip
。 否则,其高度不会被认为是所有孩子的最大高度,尽pipe它占用了额外的空间。
希望这可以帮助别人。 对不起,这是一个黑客…
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); } }
对于有这个问题和C#编写Xamarin Android的人来说,这也可能是一个快速的解决scheme:
pager.ChildViewAdded += (sender, e) => { e.Child.Measure ((int)MeasureSpecMode.Unspecified, (int)MeasureSpecMode.Unspecified); e.Parent.LayoutParameters.Height = e.Child.MeasuredHeight; };
如果您的孩子的视图高度相同,这主要是有用的。 否则,您将被要求为您检查的所有孩子存储某种“minimumHeight”值,即使这样,您也可能不希望在较小的子视图下方显示空白空间。
解决scheme本身对我来说还不够,但是这是因为我的子项目是listViews,而且他们的MeasuredHeight计算不正确。
我有一个WrapContentHeightViewPager的版本,它在API 23之前正常工作,它将根据所选的当前子视图调整父视图的高度。
升级到API 23后,它停止工作。 原来的解决scheme是使用getChildAt(getCurrentItem())
来获取当前的子视图来衡量哪些不起作用。 请参阅此处的解决scheme: 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,如果ScrollView的内容不需要对话框的全部可用高度,则该页面(以及整个对话框)应该包含WRAP_CONTENT。
现有的答案都没有完全适用于这种特定的情况。 坚持下去,这是一个颠簸的旅程。
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的测量视图和测量装饰高度的代码。 我遇到了他的图书馆的问题 – animation结构,我认为我的ScrollView不会滚动时,对话框的高度足够短,需要它。
我find了一个解决scheme,有点像这里提到的一些解决scheme的合并。
这个想法是测量ViewPager的当前视图。
扩展ViewPager:
class CalendarViewPager : ViewPager { constructor(context: Context) : super(context) {} constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {} override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { super.onMeasure(widthMeasureSpec, heightMeasureSpec) val adapter = adapter as MyPagerAdapter? val currentView = adapter?.currentView if (currentView != null) { currentView.measure(widthMeasureSpec, heightMeasureSpec) super.onMeasure(widthMeasureSpec, View.MeasureSpec.makeMeasureSpec(currentView.measuredHeight, View.MeasureSpec.EXACTLY)) return } super.onMeasure(widthMeasureSpec, heightMeasureSpec) } }
In the ViewPager adapter:
var currentView: View? = null override fun setPrimaryItem(container: ViewGroup, position: Int, obj: Any) { super.setPrimaryItem(container, position, obj) currentView = // get the view out of the obj , depending on your code }
If you use RecyclerPagerAdapter library , the way to get the "currentView" is by getting it from the pager-view-holder that you've set:
val item = obj as PagerViewHolder currentView = item.itemView