我已经设置了一个简单的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的高度:
public class WrapViewPager extends ViewPager {
View primaryView;
public WrapViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (primaryView != null) {
int height = 0;
for (int i = 0; i < getChildCount(); i++) {
if (primaryView == getChildAt(i)) {
int childHeightSpec = MeasureSpec.makeMeasureSpec(0x1 << 30 - 1, MeasureSpec.AT_MOST);
getChildAt(i).measure(widthMeasureSpec, childHeightSpec);
height = getChildAt(i).getMeasuredHeight();
}
}
setMeasuredDimension(widthMeasureSpec, MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
}
}
public void setPrimaryView(View view) {
primaryView = view;
}
}
调用setPrimaryView(视图):
public class ZGAdapter extends PagerAdapter {
@Override
public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
super.setPrimaryItem(container, position, object);
((WrapViewPager)container).setPrimaryView((View)object);
}
}
另一个更通用的解决方案是让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;
}
}
另一种解决方案是根据PagerAdapter中的当前页面高度更新ViewPager高度。假设你用这种方式创建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是动态添加到PagerAdapter的PageInfo结构的内部列表,CustomImageView只是常规的ImageView,覆盖onMeasure()方法,根据指定的宽度设置其高度并保持图像纵横比。
你可以在setPrimaryItem()方法中强制ViewPager的高度:
@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)));
}
注意数学。这修复了ViewPager不更新显示的页面(显示为空白),当前一页的高度为零时(即CustomImageView中可绘制的空),在两页之间每次奇怪的来回滑动。
我遇到了同样的问题,当用户在页面之间滚动时,我还必须让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显示的当前页面的高度。