为什么在 android 中的 sp 中设置文本大小时,静态布局对不同的屏幕密度没有响应?

问题描述

我正在使用这个 android library文字贴纸。这里是 textsticker 类的代码

    public class TextSticker extends Sticker {

  /**
   * Our ellipsis string.
   */
  private static final String mEllipsis = "\u2026";

  private final Context context;
  private final Rect realBounds;
  private final Rect textRect;
  private final TextPaint textPaint;
  private Drawable drawable;
  private StaticLayout staticLayout;
  private Layout.Alignment alignment;
  private String text;

  /**
   * Upper bounds for text size.
   * This acts as a starting point for resizing.
   */
  private float maxTextSizePixels;

  /**
   * Lower bounds for text size.
   */
  private float minTextSizePixels;

  /**
   * Line spacing multiplier.
   */
  private float li@R_502_6431@pacingMultiplier = 1.0f;

  /**
   * Additional line spacing.
   */
  private float li@R_502_6431@pacingExtra = 0.0f;

  public TextSticker(@NonNull Context context) {
    this(context,null);
  }

  public TextSticker(@NonNull Context context,@Nullable Drawable drawable) {
    this.context = context;
    this.drawable = drawable;
    if (drawable == null) {
      this.drawable = ContextCompat.getDrawable(context,R.drawable.sticker_transparent_background);
    }
    textPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
    realBounds = new Rect(0,getWidth(),getHeight());
    textRect = new Rect(0,getHeight());
    minTextSizePixels = convertSpToPx(6);
    maxTextSizePixels = convertSpToPx(32);
    alignment = Layout.Alignment.ALIGN_CENTER;
    textPaint.setTextSize(maxTextSizePixels);
  }

  @Override public void draw(@NonNull Canvas canvas) {
    Matrix matrix = getMatrix();
    canvas.save();
    canvas.concat(matrix);
    if (drawable != null) {
      drawable.setBounds(realBounds);
      drawable.draw(canvas);
    }
    canvas.restore();

    canvas.save();
    canvas.concat(matrix);
    if (textRect.width() == getWidth()) {
      int dy = getHeight() / 2 - staticLayout.getHeight() / 2;
      // center vertical
      canvas.translate(0,dy);
    } else {
      int dx = textRect.left;
      int dy = textRect.top + textRect.height() / 2 - staticLayout.getHeight() / 2;
      canvas.translate(dx,dy);
    }
    staticLayout.draw(canvas);
    canvas.restore();
  }

  @Override public int getWidth() {
    return drawable.getIntrinsicWidth();
  }

  @Override public int getHeight() {
    return drawable.getIntrinsicHeight();
  }

  @Override public void release() {
    super.release();
    if (drawable != null) {
      drawable = null;
    }
  }

  @NonNull @Override public TextSticker setAlpha(@IntRange(from = 0,to = 255) int alpha) {
    textPaint.setAlpha(alpha);
    return this;
  }

  @NonNull @Override public Drawable getDrawable() {
    return drawable;
  }

  @Override public TextSticker setDrawable(@NonNull Drawable drawable) {
    this.drawable = drawable;
    realBounds.set(0,getHeight());
    textRect.set(0,getHeight());
    return this;
  }

  @NonNull public TextSticker setDrawable(@NonNull Drawable drawable,@Nullable Rect region) {
    this.drawable = drawable;
    realBounds.set(0,getHeight());
    if (region == null) {
      textRect.set(0,getHeight());
    } else {
      textRect.set(region.left,region.top,region.right,region.bottom);
    }
    return this;
  }

  @NonNull public TextSticker setTypeface(@Nullable Typeface typeface) {
    textPaint.setTypeface(typeface);
    return this;
  }

  @NonNull public TextSticker setTextColor(@ColorInt int color) {
    textPaint.setColor(color);
    return this;
  }

  @NonNull public TextSticker setTextAlign(@NonNull Layout.Alignment alignment) {
    this.alignment = alignment;
    return this;
  }

  @NonNull public TextSticker setMaxTextSize(@Dimension(unit = Dimension.SP) float size) {
    textPaint.setTextSize(convertSpToPx(size));
    maxTextSizePixels = textPaint.getTextSize();
    return this;
  }

  /**
   * Sets the lower text size limit
   *
   * @param minTextSizeScaledPixels the minimum size to use for text in this view,* in scaled pixels.
   */
  @NonNull public TextSticker setMinTextSize(float minTextSizeScaledPixels) {
    minTextSizePixels = convertSpToPx(minTextSizeScaledPixels);
    return this;
  }

  @NonNull public TextSticker setLi@R_502_6431@pacing(float add,float multiplier) {
    li@R_502_6431@pacingMultiplier = multiplier;
    li@R_502_6431@pacingExtra = add;
    return this;
  }

  @NonNull public TextSticker setText(@Nullable String text) {
    this.text = text;
    return this;
  }

  @Nullable public String getText() {
    return text;
  }

  /**
   * Resize this view's text size with respect to its width and height
   * (minus padding). You should always call this method after the initialization.
   */
  @NonNull public TextSticker resizeText() {
    final int availableHeightPixels = textRect.height();

    final int availableWidthPixels = textRect.width();

    final CharSequence text = getText();

    // Safety check
    // (Do not resize if the view does not have dimensions or if there is no text)
    if (text == null
        || text.length() <= 0
        || availableHeightPixels <= 0
        || availableWidthPixels <= 0
        || maxTextSizePixels <= 0) {
      return this;
    }

    float targetTextSizePixels = maxTextSizePixels;
    int targetTextHeightPixels =
        getTextHeightPixels(text,availableWidthPixels,targetTextSizePixels);

    // Until we either fit within our TextView
    // or we have reached our minimum text size,// incrementally try smaller sizes
    while (targetTextHeightPixels > availableHeightPixels
        && targetTextSizePixels > minTextSizePixels) {
      targetTextSizePixels = Math.max(targetTextSizePixels - 2,minTextSizePixels);

      targetTextHeightPixels =
          getTextHeightPixels(text,targetTextSizePixels);
    }

    // If we have reached our minimum text size and the text still doesn't fit,// append an ellipsis
    // (NOTE: Auto-ellipsize doesn't work hence why we have to do it here)
    if (targetTextSizePixels == minTextSizePixels
        && targetTextHeightPixels > availableHeightPixels) {
      // Make a copy of the original TextPaint object for measuring
      TextPaint textPaintcopy = new TextPaint(textPaint);
      textPaintcopy.setTextSize(targetTextSizePixels);

      // Measure using a StaticLayout instance
      StaticLayout staticLayout =
          new StaticLayout(text,textPaintcopy,Layout.Alignment.ALIGN_norMAL,li@R_502_6431@pacingMultiplier,li@R_502_6431@pacingExtra,false);

      // Check that we have a least one line of rendered text
      if (staticLayout.getLineCount() > 0) {
        // Since the line at the specific vertical position would be cut off,// we must trim up to the prevIoUs line and add an ellipsis
        int lastLine = staticLayout.getLineForVertical(availableHeightPixels) - 1;

        if (lastLine >= 0) {
          int startOffset = staticLayout.getLi@R_502_6431@tart(lastLine);
          int endOffset = staticLayout.getLineEnd(lastLine);
          float linewidthPixels = staticLayout.getlinewidth(lastLine);
          float ellipseWidth = textPaintcopy.measureText(mEllipsis);

          // Trim characters off until we have enough room to draw the ellipsis
          while (availableWidthPixels < linewidthPixels + ellipseWidth) {
            endOffset--;
            linewidthPixels =
                textPaintcopy.measureText(text.subSequence(startOffset,endOffset + 1).toString());
          }

          setText(text.subSequence(0,endOffset) + mEllipsis);
        }
      }
    }
    textPaint.setTextSize(targetTextSizePixels);
    staticLayout =
        new StaticLayout(this.text,textPaint,textRect.width(),alignment,true);
    return this;
  }

  /**
   * @return lower text size limit,in pixels.
   */
  public float getMinTextSizePixels() {
    return minTextSizePixels;
  }

  /**
   * Sets the text size of a clone of the view's {@link TextPaint} object
   * and uses a {@link StaticLayout} instance to measure the height of the text.
   *
   * @return the height of the text when placed in a view
   * with the specified width
   * and when the text has the specified size.
   */
  protected int getTextHeightPixels(@NonNull CharSequence source,int availableWidthPixels,float textSizePixels) {
    textPaint.setTextSize(textSizePixels);
    // It's not efficient to create a StaticLayout instance
    // every time when measuring,we can use StaticLayout.Builder
    // since api 23.
    StaticLayout staticLayout =
        new StaticLayout(source,true);
    return staticLayout.getHeight();
  }

  /**
   * @return the number of pixels which scaledPixels corresponds to on the device.
   */
  private float convertSpToPx(float scaledPixels) {
    return scaledPixels * context.getResources().getdisplayMetrics().scaledDensity;
  }
}

我正在尝试将 textsticker 的坐标保存在父框架布局(lib 的 Sticker View 类)上。我将文本大小保存为 SP。然后在不同的设备上加载相同的坐标时,我将 sp 转换为 px。但问题是贴纸由于某种原因在 x 轴上偏移。基本上,即使我使用 SP 作为单位,它也不会在不同的设备上产生相同的结果。

这是保存坐标的代码

    textSizeSp = DensityUtils.px2sp(MainActivity.this,textSizePixel);

这里是加载坐标的代码

    float sizeInPx = DensityUtils.sp2px(MainActivity.this,Float.parseFloat(getSizeInSp()));

在这个库中的 Drawable Sticker 类中遇到了同样的问题。但是我通过将位图的密度设置为设备的密度来解决它。但是在 textsticker 中没有位图。静态布局正在画布上呈现。我试图设置静态布局的密度,但它没有任何这样的方法属性

知道为什么会这样吗?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)