我已经设置了一个简单的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);
Run Code Online (Sandbox Code Playgroud)
尽管将高度设置为wrap_content,但即使imageview仅为200dp,寻呼机也会填充屏幕.我试图用"200"替换寻呼机的高度,但这给了我多种分辨率的不同结果.我无法将"dp"添加到该值.如何在寻呼机的布局中添加200dp?
Dan*_*lle 390
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);
}
Run Code Online (Sandbox Code Playgroud)
cyb*_*gen 101
另一个更通用的解决方案是开始wrap_content工作.
我已经扩展ViewPager到覆盖onMeasure().高度围绕第一个子视图.如果子视图的高度不完全相同,这可能会导致意外结果.为此,可以轻松扩展该类,让我们说动画为当前视图/页面的大小.但我不需要那个.
您可以像原始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"/>
Run Code Online (Sandbox Code Playgroud)
优点:此方法允许在包括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;
}
}
Run Code Online (Sandbox Code Playgroud)
Min*_*Man 56
我的答案基于DanielLópezLacalle和这篇文章http://www.henning.ms/2013/09/09/viewpager-that-simply-dont-measure-up/.Daniel的答案的问题在于,在某些情况下,我的孩子的身高为零.不幸的是,解决方案是两次测量.
@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);
}
Run Code Online (Sandbox Code Playgroud)
如果您想要或只是wrap_content,这也允许您在ViewPager上设置高度.
Jav*_*ave 38
我刚才回答了一个非常相似的问题,当找到一个链接来支持我的索赔时碰巧找到了这个,很幸运你:)
我的另一个答案:
ViewPager不支持,wrap_content因为它(通常)不会同时加载所有子代,因此无法获得合适的大小(选项是每次切换时都有一个改变大小的寻呼机页).
但是,您可以设置精确的尺寸(例如150dp)并且match_parent也可以.
您还可以通过更改其中的height-attribute来动态修改维度LayoutParams.
根据您的需要,您可以在自己的xml文件中创建ViewPager,并将layout_height设置为200dp,然后在您的代码中,而不是从头开始创建新的ViewPager,您可以膨胀该xml文件:
LayoutInflater inflater = context.getLayoutInflater();
inflater.inflate(R.layout.viewpagerxml, layout, true);
Run Code Online (Sandbox Code Playgroud)
Raa*_*nan 16
我已经在几个项目中遇到过这个问题,但从未有过完整的解决方案.所以我创建了一个WrapContentViewPager github项目作为ViewPager的就地替代品.
https://github.com/rnevet/WCViewPager
解决方案的灵感来自于此处的一些答案,但改进了:
更新了支持库版本24,它破坏了以前的实现.
Ida*_*dan 15
我刚刚碰到了同样的问题.我有一个ViewPager,我想在它的按钮上显示一个广告.我找到的解决方案是将寻呼机放入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>
Run Code Online (Sandbox Code Playgroud)
Fel*_*hos 12
使用DanielLópezLocalle回答,我在Kotlin创建了这个课程.希望它能为您节省更多时间
class DynamicHeightViewPager @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : ViewPager(context, attrs) {
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
var heightMeasureSpec = heightMeasureSpec
var height = 0
for (i in 0 until childCount) {
val child = getChildAt(i)
child.measure(widthMeasureSpec, View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED))
val h = child.measuredHeight
if (h > height) height = h
}
if (height != 0) {
heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY)
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
}}
Run Code Online (Sandbox Code Playgroud)
我也碰到了这个问题,但在我的情况下,我有一个FragmentPagerAdapter提供ViewPager它的页面.我的问题是,onMeasure()的ViewPager任何被调用前Fragments已经建立(因此不能大小本身正确).
有点试验和错误之后,我发现finishUpdate()后的FragmentPagerAdapter的方法被调用Fragments已(从被初始化instantiateItem()的FragmentPagerAdapter),并且还经过/页面翻滚过程中.我做了一个小界面:
public interface AdapterFinishUpdateCallbacks
{
void onFinishUpdate();
}
Run Code Online (Sandbox Code Playgroud)
我传入我的FragmentPagerAdapter电话:
@Override
public void finishUpdate(ViewGroup container)
{
super.finishUpdate(container);
if (this.listener != null)
{
this.listener.onFinishUpdate();
}
}
Run Code Online (Sandbox Code Playgroud)
这反过来让我可以调用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;
}
}
Run Code Online (Sandbox Code Playgroud)
我不确定这是最好的方法,如果你认为它好/坏/邪恶会喜欢评论,但它似乎在我的实现中工作得很好:)
希望这有助于那里的人!
编辑:我忘了添加一个requestLayout()后调用super.measure()(否则它不重绘视图).
我也忘了将父级的填充添加到最终高度.
我还保留原始宽度/高度MeasureSpecs,有利于根据需要创建一个新的.已相应更新了代码.
我遇到的另一个问题是,它不会在a中正确调整大小,ScrollView并发现罪魁祸首是用MeasureSpec.EXACTLY而不是测量孩子MeasureSpec.UNSPECIFIED.更新以反映这一点.
这些更改都已添加到代码中.如果需要,您可以查看历史记录以查看旧版本(不正确).
另一种解决方案是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;
}
Run Code Online (Sandbox Code Playgroud)
哪里mPages是PageInfo动态添加到结构的内部结构列表,PagerAdapter并且CustomImageView只是常规ImageView的覆盖onMeasure()方法,根据指定的宽度设置其高度并保持图像宽高比.
您可以ViewPager在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)));
}
Run Code Online (Sandbox Code Playgroud)
请注意Math.max(height, 1).这修复了烦人的错误,ViewPager它不会更新显示的页面(显示为空白),当前一页的高度为零(即可绘制空值CustomImageView)时,每个奇数在两页之间来回滑动.
在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));
}
}
Run Code Online (Sandbox Code Playgroud)
改进了Daniel L\xc3\xb3pez Lacalle答案,用Kotlin重写:
\n\nclass MyViewPager(context: Context, attrs: AttributeSet): ViewPager(context, attrs) {\n override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {\n val zeroHeight = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)\n\n val maxHeight = children\n .map { it.measure(widthMeasureSpec, zeroHeight); it.measuredHeight }\n .max() ?: 0\n\n if (maxHeight > 0) {\n val maxHeightSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.EXACTLY)\n super.onMeasure(widthMeasureSpec, maxHeightSpec)\n return\n }\n\n super.onMeasure(widthMeasureSpec, heightMeasureSpec)\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
95825 次 |
| 最近记录: |