content: /*
   * Created by LuaView.
   * Copyright (c) 2017, Alibaba Group. All rights reserved.
   *
   * This source code is licensed under the MIT.
   * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
   */
  
  package com.taobao.luaview.util;
  
  import android.annotation.TargetApi;
  import android.content.Context;
  import android.content.res.Resources;
  import android.os.Build;
  import android.text.Layout;
  import android.text.StaticLayout;
  import android.text.TextPaint;
  import android.text.method.SingleLineTransformationMethod;
  import android.text.method.TransformationMethod;
  import android.util.DisplayMetrics;
  import android.util.Log;
  import android.util.TypedValue;
  import android.view.ViewGroup;
  import android.widget.TextView;
  
  /**
   * 文字相关的工具类
   *
   * @author song
   * @date 15/10/22
   */
  public class TextUtil {
      private static final String TAG = "TextUtil";
      private static final boolean SPEW = false;
  
      // Minimum size of the text in pixels
      private static final int DEFAULT_MIN_TEXT_SIZE = 8; //sp
      // How precise we want to be when reaching the target textWidth size
      private static final float DEFAULT_PRECISION = 0.5f;
  
      /**
       * 使文字大小适应frame
       *
       * @param view
       */
      public static void adjustTextSize(TextView view) {
          final Context context = view.getContext();
          float scaledDensity = context.getResources().getDisplayMetrics().scaledDensity;
          TextPaint paint = new TextPaint();
          int maxLines = getMaxLines(view);
          float minTextSize = scaledDensity * DEFAULT_MIN_TEXT_SIZE;
          float maxTextSize = view.getTextSize();
          float precision = DEFAULT_PRECISION;
          adjustTextSize(view, paint, minTextSize, maxTextSize, maxLines, precision);
      }
  
      /**
       * 改变外框大小，适应文字
       * 如果当前文字只有一行，则缩到外框适应文字大小
       * 如果文字有多行，则宽度不变，缩小高度到适应文字大小
       * 文字外框的位置不变
       *
       * @param view
       */
      @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
      public static void adjustSize(TextView view) {
          if (view != null && view.getLayoutParams() != null) {
              /*
              //更好的实现方式，但是ios那边不支持这种方式
              ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
              layoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT;
              layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
              view.setLayoutParams(layoutParams);*/
  
              // 废弃的实现方式，使用WRAP_CONTENT最简单，且这种方式算出来的width有bug
              // @Deprecated
              /*int lineCount = Math.min(view.getLineCount(), getMaxLines(view));
              int width, height;
              if (lineCount > 1) {//多行，宽度不变，改变高度
                  width = view.getWidth();
                  height = view.getLineHeight() * lineCount + view.getPaddingTop() + view.getPaddingBottom();
              } else {//一行，改变宽度&高度
                  final Paint paint = view.getPaint();
                  width = (int) paint.measureText(view.getText().toString()) + view.getPaddingLeft() + view.getPaddingRight();
                  height = view.getLineHeight() + view.getPaddingTop() + view.getPaddingBottom();
              }*/
  
              int lineCount = Math.min(view.getLineCount(), getMaxLines(view));
              float width, height;
              if (lineCount > 1) {//多行，宽度不变，改变高度
                  width = view.getWidth();
                  height = view.getLineHeight() * lineCount + view.getPaddingTop() + view.getPaddingBottom();
              } else {//一行，改变宽度&高度
                  width = view.getPaddingLeft() + Layout.getDesiredWidth(view.getText(), view.getPaint()) + view.getPaddingRight();
                  height = view.getLineHeight() + view.getPaddingTop() + view.getPaddingBottom();
              }
  
              if (view.getLayoutParams() != null) {
                  ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
                  layoutParams.width = (int) width;
                  layoutParams.height = (int) height;
                  view.setLayoutParams(layoutParams);
              }
          }
      }
  
      /**
       * Re-sizes the textSize of the TextView so that the text fits within the bounds of the View.
       */
      private static void adjustTextSize(TextView view, TextPaint paint, float minTextSize, float maxTextSize, int maxLines, float precision) {
          if (maxLines <= 0 || maxLines == Integer.MAX_VALUE) {
              // Don't auto-size since there's no limit on lines.
              return;
          }
  
          int targetWidth = view.getWidth() - view.getPaddingLeft() - view.getPaddingRight();
          if (targetWidth <= 0) {
              return;
          }
  
          CharSequence text = view.getText();
          TransformationMethod method = view.getTransformationMethod();
          if (method != null) {
              text = method.getTransformation(text, view);
          }
  
          Context context = view.getContext();
          Resources r = Resources.getSystem();
          DisplayMetrics displayMetrics;
  
          float size = maxTextSize;
          float high = size;
          float low = 0;
  
          if (context != null) {
              r = context.getResources();
          }
          displayMetrics = r.getDisplayMetrics();
  
          paint.set(view.getPaint());
          paint.setTextSize(size);
  
          if ((maxLines == 1 && paint.measureText(text, 0, text.length()) > targetWidth)
                  || getLineCount(text, paint, size, targetWidth, displayMetrics) > maxLines) {
              size = getAutofitTextSize(text, paint, targetWidth, maxLines, low, high, precision, displayMetrics);
          }
  
          if (size < minTextSize) {
              size = minTextSize;
          }
  
          view.setTextSize(TypedValue.COMPLEX_UNIT_PX, size);
      }
  
      /**
       * Recursive binary search to find the best size for the text.
       */
      private static float getAutofitTextSize(CharSequence text, TextPaint paint, float targetWidth, int maxLines, float low, float high, float precision, DisplayMetrics displayMetrics) {
          float mid = (low + high) / 2.0f;
          int lineCount = 1;
          StaticLayout layout = null;
  
          paint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, mid, displayMetrics));
  
          if (maxLines != 1) {
              layout = new StaticLayout(text, paint, (int) targetWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, true);
              lineCount = layout.getLineCount();
          }
  
          if (SPEW)
              Log.d(TAG, "low=" + low + " high=" + high + " mid=" + mid + " target=" + targetWidth + " maxLines=" + maxLines + " lineCount=" + lineCount);
  
          if (lineCount > maxLines) {
              // For the case that `text` has more newline characters than `maxLines`.
              if ((high - low) < precision) {
                  return low;
              }
              return getAutofitTextSize(text, paint, targetWidth, maxLines, low, mid, precision, displayMetrics);
          } else if (lineCount < maxLines) {
              return getAutofitTextSize(text, paint, targetWidth, maxLines, mid, high, precision, displayMetrics);
          } else {
              float maxLineWidth = 0;
              if (maxLines == 1) {
                  maxLineWidth = paint.measureText(text, 0, text.length());
              } else {
                  for (int i = 0; i < lineCount; i++) {
                      if (layout.getLineWidth(i) > maxLineWidth) {
                          maxLineWidth = layout.getLineWidth(i);
                      }
                  }
              }
  
              if ((high - low) < precision) {
                  return low;
              } else if (maxLineWidth > targetWidth) {
                  return getAutofitTextSize(text, paint, targetWidth, maxLines, low, mid, precision, displayMetrics);
              } else if (maxLineWidth < targetWidth) {
                  return getAutofitTextSize(text, paint, targetWidth, maxLines, mid, high, precision, displayMetrics);
              } else {
                  return mid;
              }
          }
      }
  
      private static int getLineCount(CharSequence text, TextPaint paint, float size, float width, DisplayMetrics displayMetrics) {
          paint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, size, displayMetrics));
          StaticLayout layout = new StaticLayout(text, paint, (int) width, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, true);
          return layout.getLineCount();
      }
  
      private static int getMaxLines(TextView view) {
          int maxLines = -1; // No limit (Integer.MAX_VALUE also means no limit)
  
          TransformationMethod method = view.getTransformationMethod();
          if (method != null && method instanceof SingleLineTransformationMethod) {
              maxLines = 1;
          } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
              // setMaxLines() and getMaxLines() are only available on android-16+
              maxLines = view.getMaxLines();
          }
  
          return maxLines;
      }
  }
  