测量ViewPager

Saa*_*ooq 18 android android-viewpager

我有一个有孩子的自定义ViewGroup ViewPager.该ViewPager由供给PagerAdapter,其提供LinearLayoutViewPager其具有LayoutParamsWRAP_CONTENT在两个高度和宽度.

视图显示正确,但在child.measure()ViewPager上调用方法时,它不返回LinearLayout的实际尺寸,但似乎填充了所有剩余空间.

任何想法为什么会发生这种情况以及如何修改它?

Del*_*yan 55

我对接受的答案(也没有评论中的预膨胀全视图解决方案)感到不满意,所以我把ViewPager第一个可用孩子的高度放在一起.它通过执行第二次测量传递来实现此目的,允许您窃取第一个孩子的身高.

一个更好的解决方案是在android.support.v4.view包中创建一个新类,实现更好的版本onMeasure(可以访问包可见的方法populate())

但就目前而言,下面的解决方案很适合我.

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);

        boolean wrapHeight = MeasureSpec.getMode(heightMeasureSpec) 
                == MeasureSpec.AT_MOST;

        if(wrapHeight) {
            /**
             * The first super.onMeasure call made the pager take up all the 
             * available height. Since we really wanted to wrap it, we need 
             * to remeasure it. Luckily, after that call the first child is 
             * now available. So, we take the height from it. 
             */

            int width = getMeasuredWidth(), height = getMeasuredHeight();

            // Use the previously measured width but simplify the calculations
            widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);

            /* If the pager actually has any children, take the first child's 
             * height and call that our own */ 
            if(getChildCount() > 0) {
                View firstChild = getChildAt(0);

                /* The child was previously measured with exactly the full height.
                 * Allow it to wrap this time around. */
                firstChild.measure(widthMeasureSpec, 
                        MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST));

                height = firstChild.getMeasuredHeight();
            }

            heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);

            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我不知道是否有人遇到麻烦,但这不起作用,我将`MeasureSpec.AT_MOST`更改为`MeasureSpec.UNSPECIFIED`,因为`heightMeasureSpec`参数为0.它有效...... (5认同)

Nic*_*ion 12

在兼容性jar中查看ViewPager类的内部:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
    // For simple implementation, or internal size is always 0.
    // We depend on the container to specify the layout size of
    // our view. We can't really know what it is since we will be
    // adding and removing different arbitrary views and do not
    // want the layout to change as this happens.
    setMeasuredDimension(getDefaultSize(0, widthMeasureSpec), getDefaultSize(0, heightMeasureSpec));

   ...
}
Run Code Online (Sandbox Code Playgroud)

看起来ViewPager实现不会测量子视图,而只是根据父传入的内容将ViewPager设置为一个标准视图.当您传递wrap_content时,由于视图寻呼机实际上没有测量其内容所需完整的可用区域.

我的建议是根据子视图的大小在ViewPager上设置静态大小.如果这是不可能的(例如,子视图可能不同),您需要选择最大大小并在某些视图中处理额外空间或扩展ViewPager并提供测量子视图的onMeasure.您将遇到的一个问题是,视图寻呼机的设计宽度不同,因为显示了不同的视图,因此您可能会被迫选择一个大小并继续使用它

  • 你能否分享一下你如何通过EXACT MeasureSpec?提前致谢. (2认同)