围绕 ImageSpan 中心垂直对齐文本 [英] Align text around ImageSpan center vertical

查看:29
本文介绍了围绕 ImageSpan 中心垂直对齐文本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 ImageSpan 一段文字的内部.我注意到周围的文本总是绘制在文本行的底部——更准确地说,文本行的大小随着图像的增长而增长,但文本的基线不会向上移动.当图像明显大于文本大小时,效果相当难看.

I have an ImageSpan inside of a piece of text. What I've noticed is that the surrounding text is always drawn at the bottom of the text line -- to be more precise, the size of the text line grows with the image but the baseline of the text does not shift upward. When the image is noticeably larger than the text size, the effect is rather unsightly.

这是一个示例,轮廓显示了 TextView 的边界:

Here is a sample, the outline shows bounds of the TextView:

我试图让周围的文本相对于显示的图像垂直居中.以下是显示所需位置的蓝色文本示例:

I am trying to have the surrounding text be centered vertically with respect to the image being displayed. Here is the same sample with blue text showing the desired location:

以下是我受到的约束:

  • 我不能使用复合绘图.图像必须能够显示在单词之间.
  • 文本可能是多行的,具体取决于内容.我无法控制这一点.
  • 我的图片比周围的文字大,我无法缩小它们的大小.虽然上面的示例图片比实际图片大(以演示当前的行为),但实际图片仍然足够大,这个问题很明显.

我尝试在 TextView 上使用 android:gravity="center_vertical" 属性,但这没有任何效果.我相信这只是垂直居中文本 lines,但在文本行内,文本仍然绘制在底部.

I've tried using the android:gravity="center_vertical" attribute on the TextView, but this does not have any effect. I believe this just vertically centers the text lines, but within the text line the text is still drawn at the bottom.

我目前的思路是创建一个自定义跨度,根据行高和当前文本大小移动文本的基线.这个跨度将包含整个文本,我必须计算与 ImageSpan 的交集,这样我也可以避免移动图像.这听起来相当令人生畏,我希望有人可以提出另一种方法.

My current train of thought is to create a custom span that shifts the baseline of the text based on the height of the line and the current text size. This span would encompass the entire text, and I would have to compute the intersection with the ImageSpans so I can avoid shifting the images as well. This sounds rather daunting and I'm hoping someone can suggest another approach.

感谢所有帮助!

推荐答案

现在可能有点晚了,但我已经找到了一种方法,无论图像大小如何.您需要创建一个扩展 ImageSpan 的类并覆盖方法 getSize()getCachedDrawable()(我们不需要更改最后一个,但是该方法来自 DynamicDrawableSpan 是私有的,不能从子类以其他方式访问).在getSize(...)中,您可以重新定义DynamicDrawableSpan设置行的上升/顶部/下降/底部的方式,并实现您想要做的.

It might be a bit late but I've found a way to do it, no matter the image size. You need to create a class extending ImageSpan and override the methods getSize() and getCachedDrawable() (we don't need to change the last one, but this method from DynamicDrawableSpan is private and cannot be accessed in another way from the child class). In getSize(...), you can then redefined the way DynamicDrawableSpan set the ascent/top/descent/bottom of the line and achieve what you want to do.

这是我的课堂示例:

import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.text.style.DynamicDrawableSpan;
import android.text.style.ImageSpan;

import java.lang.ref.WeakReference;

public class CenteredImageSpan extends ImageSpan {

    // Extra variables used to redefine the Font Metrics when an ImageSpan is added
    private int initialDescent = 0;
    private int extraSpace = 0;

    public CenteredImageSpan(final Drawable drawable) {
        this(drawable, DynamicDrawableSpan.ALIGN_BOTTOM);
    }

    public CenteredImageSpan(final Drawable drawable, final int verticalAlignment) {
        super(drawable, verticalAlignment);
    }

    @Override
    public void draw(Canvas canvas, CharSequence text,
                     int start, int end, float x,
                     int top, int y, int bottom, Paint paint) {
        getDrawable().draw(canvas);
    }

    // Method used to redefined the Font Metrics when an ImageSpan is added
    @Override
    public int getSize(Paint paint, CharSequence text,
                       int start, int end,
                       Paint.FontMetricsInt fm) {
        Drawable d = getCachedDrawable();
        Rect rect = d.getBounds();

        if (fm != null) {
            // Centers the text with the ImageSpan
            if (rect.bottom - (fm.descent - fm.ascent) >= 0) {
                // Stores the initial descent and computes the margin available
                initialDescent = fm.descent;
                extraSpace = rect.bottom - (fm.descent - fm.ascent);
            }

            fm.descent = extraSpace / 2 + initialDescent;
            fm.bottom = fm.descent;

            fm.ascent = -rect.bottom + fm.descent;
            fm.top = fm.ascent;
        }

        return rect.right;
    }

    // Redefined locally because it is a private member from DynamicDrawableSpan
    private Drawable getCachedDrawable() {
        WeakReference<Drawable> wr = mDrawableRef;
        Drawable d = null;

        if (wr != null)
            d = wr.get();

        if (d == null) {
            d = getDrawable();
            mDrawableRef = new WeakReference<>(d);
        }

        return d;
    }

    private WeakReference<Drawable> mDrawableRef;
}

如果您在该课程中遇到任何问题,请告诉我!

Let me know if you have any trouble with that class!

这篇关于围绕 ImageSpan 中心垂直对齐文本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆