Автоматическое масштабирование текста TextView для размещения в пределах - PullRequest
789 голосов
/ 17 февраля 2011

Я ищу оптимальный способ изменить размер переноса текста в TextView, чтобы он соответствовал границам getHeight и getWidth. Я не просто ищу способ обернуть текст - я хочу убедиться, что он оборачивается и достаточно мал, чтобы поместиться полностью на экране.

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

Но я уверен, что кто-то нашел хорошее решение, которое не включает в себя то, что я делаю: написание нескольких сложных подпрограмм, которые анализируют и измеряют текст, изменяют размер текста и повторяют до тех пор, пока не будет достаточно небольшого размера был найден

Какие процедуры TextView использует для переноса текста? Разве их нельзя как-то использовать, чтобы предсказать, будет ли текст достаточно маленьким?

tl; dr : существует ли наилучший способ автоматического изменения размера TextView для подгонки, обтекания в границах getHeight и getWidth?

Ответы [ 33 ]

0 голосов
/ 18 июля 2015

См. ScalableTextView.java здесь Автоматическая подгонка TextView для Android .Я добавил код для сжатия и расширения TextView на основе длины текста

0 голосов
/ 08 декабря 2014

Расширение TextView и переопределение onDraw с кодом ниже.Он сохранит соотношение сторон текста, но увеличит его, чтобы заполнить пространство.Вы можете легко изменить код, чтобы растянуть при необходимости.

  @Override
  protected void onDraw(@NonNull Canvas canvas) {
    TextPaint textPaint = getPaint();
    textPaint.setColor(getCurrentTextColor());
    textPaint.setTextAlign(Paint.Align.CENTER);
    textPaint.drawableState = getDrawableState();

    String text = getText().toString();
    float desiredWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight() - 2;
    float desiredHeight = getMeasuredHeight() - getPaddingTop() - getPaddingBottom() - 2;
    float textSize = textPaint.getTextSize();

    for (int i = 0; i < 10; i++) {
      textPaint.getTextBounds(text, 0, text.length(), rect);
      float width = rect.width();
      float height = rect.height();

      float deltaWidth = width - desiredWidth;
      float deltaHeight = height - desiredHeight;

      boolean fitsWidth = deltaWidth <= 0;
      boolean fitsHeight = deltaHeight <= 0;

      if ((fitsWidth && Math.abs(deltaHeight) < 1.0)
          || (fitsHeight && Math.abs(deltaWidth) < 1.0)) {
        // close enough
        break;
      }

      float adjustX = desiredWidth / width;
      float adjustY = desiredHeight / height;

      textSize = textSize * (adjustY < adjustX ? adjustY : adjustX);

      // adjust text size
      textPaint.setTextSize(textSize);
    }
    float x = desiredWidth / 2f;
    float y = desiredHeight / 2f - rect.top - rect.height() / 2f;
    canvas.drawText(text, x, y, textPaint);
  }
0 голосов
/ 31 июля 2013

Вот подход, который я использую. Это очень просто Он использует последовательное приближение к нулю на размере шрифта и может вычислить его менее чем за 10 итераций. Просто замените «activityWidth» на ширину любого вида, который вы используете для отображения текста. В моем примере он устанавливается как частное поле ширины экрана. Начальный размер шрифта 198 устанавливается только в том случае, если метод генерирует исключение (которое действительно никогда не должно происходить):

  private float GetFontSizeForScreenWidth(String text)
  {
    float fontsize = 198;

    try
    {
      Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
      paint.setColor(Color.RED);
      Typeface typeface = Typeface.create("Helvetica", Typeface.BOLD);
      paint.setTypeface(typeface);
      paint.setTextAlign(Align.CENTER);

      int lowVal = 0;
      int highVal = 2000;
      int currentVal = highVal;

      /*
       * Successively approximate the screen size until it is 
       * within 2 pixels of the maximum screen width. Generally
       * this will get you to the closest font size within about 10
       * iterations.
       */

      do
      {
        paint.setTextSize(currentVal);
        float textWidth = paint.measureText(text);

        float diff = activityWidth - textWidth;

        if ((diff >= 0) && (diff <= 2))
        {
          fontsize = paint.getTextSize();
          return fontsize;
        }

        if (textWidth > activityWidth)
          highVal = currentVal;
        else if (textWidth < activityWidth)
          lowVal = currentVal;
        else
        {
          fontsize = paint.getTextSize();
          return fontsize;
        }

        currentVal = (highVal - lowVal) / 2 + lowVal;

      } while (true);      
    }
    catch (Exception ex)
    {
      return fontsize;
    }
  }
...