8

最近、カスタム ViewGroup の作成に取り掛かりましたが、理解できない問題に遭遇しました。

ViewManager と Article の 2 つの ViewGroups があります。

ViewManager は、前の記事の下に単純に記事をレイアウトします (つまり、垂直の LinearLayout のように)。

記事では、画像でわかるように、いくつかの TextView と ImageView を配置しています。単一の記事を作成して ViewManager に追加すると正常に動作し、すべてが表示されますが、2 番目の記事を追加すると記事のコンテンツが表示されません。

表示されていない 2 番目のビューを示します

では、TextView や ImageView が表示されないのはなぜですか (青色のバーは onDraw() の canvas.drawRect() で描画されることに注意してください)。また、(logcat を介して) 子ビューのバインドされた値 (getLeft()/Top()/Right()/Bottom() in drawChild()) を出力しましたが、それらはすべて問題ないように見えます

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

それで、誰かが私が間違ったことを知っていますか?

Article 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)
4

1 に答える 1

9

ではonLayout、子は親に対して配置する必要があります。子の座標にtop(および) を追加しています。とがゼロleftであるため、最初の記事では問題ありません。2 番目の記事については、まだゼロですが、ViewManager の 2 番目の記事のトップです。それぞれを取り除き、代わりに使用するだけです。topleftlefttopnewTopnewLeftmarginTopouterMargin

余談ですが、 の最初の引数makeMeasureSpecは次元であると想定されています。WRAP_CONTENT を使用すると、最大次元が -2 に設定されますが、これはおそらくやりたいことではありません。

于 2012-01-02T04:15:52.953 に答える