我已经设置了一个简单的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);
尽管高度设置为wrap_content,但即使imageview只有200dp,分页器也总是充满屏幕。我尝试用“200”替换寻呼机的高度,但在不同分辨率下会得到不同的结果。我无法将“dp”添加到该值。如何将200dp添加到寻呼机的布局?
以上建议对我都没用。我的用例是在ScrollView中有4个自定义ViewPagers。它们的顶部是基于纵横比测量的,其余的只是layout_height=wrap_content。我试过cybergen, Daniel López Lacalle解决方案。没有一个是完全适合我的。
我猜为什么cybergen不能在页面> 1上工作是因为它基于第1页计算寻呼机的高度,如果你进一步滚动,这是隐藏的。
cybergen和Daniel López Lacalle建议在我的情况下都有奇怪的行为:3个中的2个加载ok, 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>
请注意,如果所有页面都具有相同的高度,则此解决方案非常有效。否则,你需要基于当前的子活动重新计算ViewPager的高度。我不需要它,但如果你提出解决方案,我很乐意更新答案。
我只是在回答一个非常类似的问题,在寻找一个链接来支持我的说法时,碰巧发现了这个,你很幸运:)
我的另一个回答是:
ViewPager不支持wrap_content,因为它(通常)不会同时加载所有的子页面,因此无法获得适当的大小(可以选择在每次切换页面时改变大小)。
然而,你可以设置一个精确的尺寸(例如150dp)和match_parent也可以。
您还可以通过更改其LayoutParams中的height-属性,从代码中动态修改维度。
根据你的需要,你可以在它自己的xml文件中创建ViewPager, 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只调整到当前可见的子节点(不是它实际的最大子节点)
这个想法来自https://stackoverflow.com/a/56325869/4718406
public class DynamicHeightViewPager extends ViewPager {
public DynamicHeightViewPager (Context context) {
super(context);
initPageChangeListener();
}
public DynamicHeightViewPager (Context context, AttributeSet attrs) {
super(context, attrs);
initPageChangeListener();
}
private void initPageChangeListener() {
addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
requestLayout();
}
});
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//View child = getChildAt(getCurrentItem());
View child = getCurrentView(this);
if (child != null) {
child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0,
MeasureSpec.UNSPECIFIED));
int h = child.getMeasuredHeight();
heightMeasureSpec = MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
View getCurrentView(ViewPager viewPager) {
try {
final int currentItem = viewPager.getCurrentItem();
for (int i = 0; i < viewPager.getChildCount(); i++) {
final View child = viewPager.getChildAt(i);
final ViewPager.LayoutParams layoutParams = (ViewPager.LayoutParams)
child.getLayoutParams();
Field f = layoutParams.getClass().getDeclaredField("position");
//NoSuchFieldException
f.setAccessible(true);
int position = (Integer) f.get(layoutParams); //IllegalAccessException
if (!layoutParams.isDecor && currentItem == position) {
return child;
}
}
} catch (NoSuchFieldException e) {
e.fillInStackTrace();
} catch (IllegalArgumentException e) {
e.fillInStackTrace();
} catch (IllegalAccessException e) {
e.fillInStackTrace();
}
return null;
}
}