【问题标题】:Views within a Custom ViewGroup are not showing自定义视图组中的视图未显示
【发布时间】:2012-01-02 02:06:41
【问题描述】:

我最近深入研究了创建自定义 ViewGroup,但遇到了一个我无法弄清楚的问题。

我有 2 个 ViewGroups - ViewManager 和 Article

ViewManager 只是在上一篇文章下方布置一篇文章(即像垂直线性布局)

Article 排列了几个 TextView 和一个 ImageView,如图所示。创建单个文章并将其添加到 ViewManager 可以正常工作,并且所有内容都会显示,但是当我添加第二个文章时,文章的任何内容都不可见。

那么为什么没有 TextViews 或 ImageView 出现(注意蓝色条是使用 onDraw() 中的 canvas.drawRect() 绘制的)。我还打印了(通过 logcat)子视图的绑定值(即 drawChild() 中的 getLeft()/Top()/Right()/Bottom(),它们看起来都很好

FIRST TextView
FIRST left 5 right 225 top 26 bottom 147
FIRST TextView
FIRST left 5 right 320 top 147 bottom 198
FIRST TextView
FIRST left 5 right 180 top 208 bottom 222
FIRST ImageView
FIRST left 225 right 315 top 34 bottom 129
SECOND TextView
SECOND left 10 right 53 top 238 bottom 257
SECOND TextView
SECOND left 5 right 325 top 257 bottom 349
SECOND TextView
SECOND left 5 right 320 top 349 bottom 400
SECOND TextView
SECOND left 5 right 180 top 410 bottom 424

那么有人知道我做错了什么吗?

文章onMeasure方法

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
    int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
    int widthSpecSize =  MeasureSpec.getSize(widthMeasureSpec);

    int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
    int heightSpecSize =  MeasureSpec.getSize(heightMeasureSpec);
    specWidth = widthSpecSize;
    int totalHeight=0;

    int width = 0;
    if(mImage!=null&&mImage.getParent()!=null){
        measureChild(mImage,MeasureSpec.makeMeasureSpec(100, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(100, MeasureSpec.AT_MOST));
        width=widthSpecSize-mImage.getWidth();
        imageWidth = mImage.getMeasuredWidth();
    }
    for(int i = 0;i<this.getChildCount();i++){
        final View child = this.getChildAt(i);

        //get the width of the available view minus the image width
        if(imageWidth > 0)
            width =widthSpecSize- imageWidth; 
        else
            width = widthSpecSize;

        //measure only the textviews
        if(!(child instanceof ImageView)){
            measureChild(child, MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), heightMeasureSpec);
            //calculate total height of the views, used to set the dimension
            totalHeight+=child.getMeasuredHeight();
        }
    }
    //if the title height is greater than the image then the snippet
    //can stretch to full width
    if(mTitle.getMeasuredHeight()>mImage.getMeasuredHeight())
        measureChild(mSnippet, MeasureSpec.makeMeasureSpec(widthSpecSize, MeasureSpec.AT_MOST), heightMeasureSpec);

    //measure source to make it full width
    measureChild(mSource,MeasureSpec.makeMeasureSpec(LayoutParams.WRAP_CONTENT, MeasureSpec.AT_MOST), heightMeasureSpec);
    setMeasuredDimension(widthSpecSize, totalHeight);
}

和onLayout方法

protected void onLayout(boolean changed, int left, int top, int right, int bottom) {

    int newLeft = left+outerMargin;
    int newTop = top+marginTop;
    int prevHeight = 0;

    if(mEngine!=null){

        int height = mEngine.getMeasuredHeight();
        int childRight = newLeft+mEngine.getMeasuredWidth(); 
        mEngine.layout(newLeft+marginLeft, newTop+prevHeight+2, childRight+marginLeft, newTop+height+prevHeight+2);
        maxRight = Math.max(maxRight, childRight);
        prevHeight += height+2;
        topBarHeight = mEngine.getMeasuredHeight()+(marginLeft*2);
        maxBottom = Math.max(maxBottom, mEngine.getBottom());
    }
    if(mTitle!=null){
        int height = mTitle.getMeasuredHeight();
        int childRight = newLeft+mTitle.getMeasuredWidth();
        mTitle.layout(newLeft, newTop+prevHeight, childRight, newTop+height+prevHeight);
        maxRight = Math.max(maxRight, childRight);
        prevHeight += height;
        maxBottom = Math.max(maxBottom, mTitle.getBottom());
    }
    if(mSnippet!=null){
        int height = mSnippet.getMeasuredHeight();
        int childRight = newLeft+mSnippet.getMeasuredWidth();
        mSnippet.layout(newLeft, newTop+prevHeight, right, newTop+height+prevHeight);
        maxRight = Math.max(maxRight, childRight);
        prevHeight += height;
        maxBottom = Math.max(maxBottom, mSnippet.getBottom());
    }
    if(mSource !=null){
        int height = mSource.getMeasuredHeight();
        int childRight = newLeft+mSource.getMeasuredWidth();
        mSource.layout(newLeft, newTop+prevHeight+(marginTop*2), childRight, newTop+height+prevHeight+(marginTop*2));
        maxRight = Math.max(maxRight, childRight);
        prevHeight += height;
        maxBottom = Math.max(maxBottom, mSource.getBottom());

    }
    if(mImage!=null){
        int height = mImage.getMeasuredHeight();
        log("mxW "+maxRight);
        int childRight = maxRight+mImage.getMeasuredWidth();
        mImage.layout(right-mImage.getMeasuredWidth()+5, newTop+topBarHeight, right-5, height+topBarHeight);
        totalWidth = childRight;
        maxBottom = Math.max(maxBottom, mImage.getBottom());
    }else
        totalWidth = maxRight;

}

顺便说一句,可以像这样使用 LayoutParams.WRAP_CONTENT 作为 makeMeasureSpec() 的参数吗?

MeasureSpec.makeMeasureSpec(LayoutParams.WRAP_CONTENT, MeasureSpec.AT_MOST)

【问题讨论】:

  • 你能发布正确的答案吗?我不明白

标签: android android-layout android-custom-view viewgroup


【解决方案1】:

onLayout 中,子级应相对于其父级定位。您正在将top(和left)添加到孩子的坐标中。这对于第一篇文章来说不是问题,因为topleft 为零。对于第二篇文章,left 仍然为零,但 top 是其 ViewManager 中第二篇文章的顶部。只需去掉 newTopnewLeft 并分别使用 marginTopouterMargin 代替它们。

关于你:makeMeasureSpec 的第一个参数应该是一个维度。通过使用 WRAP_CONTENT,您将最大维度设置为 -2,这可能不是您想要做的。

【讨论】:

  • 支持 在 onLayout 中,子级应相对于其父级定位
  • 对我来说,问题是我覆盖了自定义视图的 OnLayout 方法,因为我继承了 ViewGroup,但我没有在 OnLayout 中添加任何实现代码。我不必在 OnLayout 中编写讨厌的定位代码,而是从 RelativeLayout 继承,然后我可以完全删除 OnLayout 方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-18
  • 1970-01-01
  • 1970-01-01
  • 2020-01-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多