TextView.onDraw вызывает бесконечный цикл

1

Я хочу, чтобы TextView корректировал размер шрифта, чтобы текст в представлении автоматически расширялся (или уменьшался), чтобы заполнить всю ширину представления. Я думал, что смогу сделать это, создав настраиваемый TextView, который переопределяет onDraw() следующим образом:

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

Тем не менее, это отправляет приложение в бесконечный цикл (при этом размер шрифта растет и уменьшается каждый раз!), поэтому я явно об этом не так. Вызывает ли вызов setTextSize() действие invalidate, так что onDraw вызывается снова, бесконечно?

Есть ли способ предотвратить рекурсивный вызов (если это происходит)? Или я должен идти об этом совершенно по-другому?

Теги:

2 ответа

3
Лучший ответ

Вызывается вызов setTextSize() invalidate, так что onDraw вызывается снова, бесконечно?

Да, возможно, что происходит. Если вы посмотрите исходный код setTextSize, вы увидите, что он вызовет этот метод:

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

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

Итак, если вы выполняете тяжелую работу по переопределению метода onDraw, почему бы вам не использовать непосредственно некоторые из drawText методов Canvas class?

  • 0
    Это фантастично! Смотрите ниже мой полный ответ. Спасибо Крис
3

Это фантастика! Престижность! Я все еще приспосабливаюсь к этому чудесному миру, в котором мы живем, где мы можем просто посмотреть исходный код, чтобы узнать, что происходит...

В интересах любого, кто может быть заинтересован, я использовал ярлык метода TextPaint.setTextSize() вместо того, чтобы вникать в Canvas.drawText(), поэтому мой onDraw() теперь выглядит следующим образом:

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

... и это работает. Спасибо!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню