开发者

TextView.onDraw causing endless loop

I want a TextView which adjusts the font size so that the text in the view will automatically expand (or shrink) to fill the full width of the view. I thought I might be able to do this by creating a customised TextView which overrides onDraw() as follows:

public class MaximisedTextView extends TextView {
    // (calls to super constructors here...)

    开发者_如何学运维@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        TextPaint textPaint = this.getPaint();
        Rect bounds = new Rect();

        String text = (String)this.getText(); // current text in view
        float textSize = this.getTextSize();  // current font size
        int viewWidth = this.getWidth() - this.getPaddingLeft() - this.getPaddingRight();
        textPaint.getTextBounds(text, 0, text.length(), bounds);
        int textWidth = bounds.width();

        // reset font size to make text fill full width of this view
        this.setTextSize(textSize * viewWidth/textWidth);
    }
}

However, this sends the app into an endless loop (with the text size growing and shrinking slightly each time!), so I'm clearly going about it the wrong way. Does the call to setTextSize() trigger an invalidate so that onDraw is called again, endlessly?

Is there a way I can prevent the recursive call (if that's what is happening)? Or should I be going about it a completely different way?


Does the call to setTextSize() trigger an invalidate so that onDraw is called again, endlessly?

Yes, that's probably what is hapening. If you take a look of the source code of setTextSize you will see that it will call this method:

private void setRawTextSize(float size) {
    if (size != mTextPaint.getTextSize()) {
        mTextPaint.setTextSize(size);

        if (mLayout != null) {
            nullLayouts();
            requestLayout();
            invalidate(); // yeahh... invalidate XD
        }
    }
}

So, if you are doing the hard work of overriding the onDraw method, why don't you use directly some of the drawText methods of the Canvas class?


That's fantasic! Kudos! I'm still adjusting to this wonderful world we live in where we can just look at the source code to see what's going on...

For the benefit of anyone else who might be interested, I took the shortcut of using the TextPaint.setTextSize() method rather than delving into Canvas.drawText(), so my onDraw() is now as follows:

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    TextPaint textPaint = this.getPaint();
    Rect bounds = new Rect();

    String text = (String)this.getText();
    float textSize = this.getTextSize();
    int viewWidth = this.getWidth() - this.getPaddingLeft() - this.getPaddingRight();
    textPaint.getTextBounds(text, 0, text.length(), bounds);
    int textWidth = bounds.width();

    float newTextSize = (float)Math.floor(textSize * viewWidth/textWidth);

    // note: adapted from TextView.setTextSize(), removing invalidate() call:

    // get the raw text size...
    Context c = getContext();
    Resources r = c==null ? Resources.getSystem() : c.getResources();
    int unit = TypedValue.COMPLEX_UNIT_SP;
    float rawSize = TypedValue.applyDimension(unit, newTextSize, r.getDisplayMetrics());

    // ... and apply it directly to the TextPaint
    textPaint.setTextSize(rawSize);
}

... and it works a treat. Thanks!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜