我已经设置了一个简单的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添加到寻呼机的布局?
如果你正在使用的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中,你必须添加PagerTitleStrip的measuredHeight,如果找到一个。否则,即使它占用了额外的空间,它的高度也不会被认为是所有子结点的最大高度。
希望这能帮助到其他人。很抱歉,这有点黑…
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);
}
}
给ViewPager的父布局NestedScrollView
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:fillViewport="true">
<androidx.viewpager.widget.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</androidx.viewpager.widget.ViewPager>
</androidx.core.widget.NestedScrollView>
别忘了设置android:fillViewport="true"
这将拉伸滚动视图及其子内容以填充视口。
https://developer.android.com/reference/android/widget/ScrollView.html#attr_android:fillViewport
另一个更通用的解决方案是让wrap_content正常工作。
我已经扩展了ViewPager来覆盖onMeasure()。高度被包裹在第一个子视图周围。如果子视图的高度不完全相同,这可能会导致意想不到的结果。因此,类可以很容易地扩展,让我们说动画到当前视图/页面的大小。但我不需要。
你可以在yout XML布局中使用这个ViewPager,就像原来的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元素。
还有一个缺点:如果你想使用页边距,你必须创建两个嵌套的布局,并给内部的一个指定所需的页边距。
代码如下:
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;
}
}
改进丹尼尔López Lacalle回答,重写在Kotlin:
class MyViewPager(context: Context, attrs: AttributeSet): ViewPager(context, attrs) {
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val zeroHeight = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
val maxHeight = children
.map { it.measure(widthMeasureSpec, zeroHeight); it.measuredHeight }
.max() ?: 0
if (maxHeight > 0) {
val maxHeightSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.EXACTLY)
super.onMeasure(widthMeasureSpec, maxHeightSpec)
return
}
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中,你必须添加PagerTitleStrip的measuredHeight,如果找到一个。否则,即使它占用了额外的空间,它的高度也不会被认为是所有子结点的最大高度。
希望这能帮助到其他人。很抱歉,这有点黑…
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);
}
}