Kar*_*uri 39 android text spannable imagespan
我有ImageSpan
一段文字.我注意到的是,周围的文本总是在文本行的底部绘制 - 更准确地说,文本行的大小随着图像的增长而增加,但文本的基线不会向上移动.当图像明显大于文本大小时,效果相当难看.
这是一个示例,大纲显示的界限TextView
:
我试图让周围的文本相对于正在显示的图像垂直居中.以下是蓝色文本显示所需位置的相同示例:
以下是我受约束的约束:
我已尝试android:gravity="center_vertical"
在TextView上使用该属性,但这没有任何效果.我认为这只是文本行的垂直居中,但在文本行中,文本仍然在底部绘制.
我目前的思路是创建一个自定义跨度,根据行的高度和当前文本大小来移动文本的基线.这个跨度将包含整个文本,我将不得不计算与ImageSpan
s 的交集,所以我也可以避免移动图像.这听起来相当令人生畏,我希望有人能提出另一种方法.
任何和所有的帮助表示赞赏!
mis*_*032 63
我的回答调整了第一个答案.实际上我已经尝试了上述两种方法,我认为它们并不是真正的中心垂直方向.这将使更多的绘制中心,如果它放在之间ascent
和descent
,而不是top
和bottom
.因此,对于第二个答案,它将drawable的中心与文本的基线对齐,而不是该文本的中心.这是我的解决方案:
public class CenteredImageSpan extends ImageSpan {
private WeakReference<Drawable> mDrawableRef;
public CenteredImageSpan(Context context, final int drawableRes) {
super(context, drawableRes);
}
@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) {
Paint.FontMetricsInt pfm = paint.getFontMetricsInt();
// keep it the same as paint's fm
fm.ascent = pfm.ascent;
fm.descent = pfm.descent;
fm.top = pfm.top;
fm.bottom = pfm.bottom;
}
return rect.right;
}
@Override
public void draw(@NonNull Canvas canvas, CharSequence text,
int start, int end, float x,
int top, int y, int bottom, @NonNull Paint paint) {
Drawable b = getCachedDrawable();
canvas.save();
int drawableHeight = b.getIntrinsicHeight();
int fontAscent = paint.getFontMetricsInt().ascent;
int fontDescent = paint.getFontMetricsInt().descent;
int transY = bottom - b.getBounds().bottom + // align bottom to bottom
(drawableHeight - fontDescent + fontAscent) / 2; // align center to center
canvas.translate(x, transY);
b.draw(canvas);
canvas.restore();
}
// 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;
}
}
Run Code Online (Sandbox Code Playgroud)
我也重写getSize
以保持FontMetrics的drawable与其他文本相同,否则父视图将不会正确地包装内容.
juj*_*789 28
可能有点晚了,但无论图像大小如何,我都找到了一种方法.您需要创建一个扩展ImageSpan的类并覆盖这些方法,getSize()
并且getCachedDrawable()
(我们不需要更改最后一个方法,但此方法DynamicDrawableSpan
是私有的,不能以其他方式从子类访问).在getSize(...)
,你就可以重新定义的方式DynamicDrawableSpan
设置直线上升/顶/下降/底层实现你想要做什么.
这是我的班级示例:
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;
}
Run Code Online (Sandbox Code Playgroud)
如果您对该课程有任何疑问,请告诉我!
boi*_*ter 22
ImageSpan imageSpan = new ImageSpan(d, ImageSpan.ALIGN_BOTTOM) {
public void draw(Canvas canvas, CharSequence text, int start,
int end, float x, int top, int y, int bottom,
Paint paint) {
Drawable b = getDrawable();
canvas.save();
int transY = bottom - b.getBounds().bottom;
// this is the key
transY -= paint.getFontMetricsInt().descent / 2;
canvas.translate(x, transY);
b.draw(canvas);
canvas.restore();
}
};
Run Code Online (Sandbox Code Playgroud)
小智 20
在阅读了TextView的源代码之后,我想我们可以使用"y"的eache文本行的baseLine.即使你设置了lineSpaceExtra它也能工作.
public class VerticalImageSpan extends ImageSpan {
public VerticalImageSpan(Drawable drawable) {
super(drawable);
}
/**
* update the text line height
*/
@Override
public int getSize(Paint paint, CharSequence text, int start, int end,
Paint.FontMetricsInt fontMetricsInt) {
Drawable drawable = getDrawable();
Rect rect = drawable.getBounds();
if (fontMetricsInt != null) {
Paint.FontMetricsInt fmPaint = paint.getFontMetricsInt();
int fontHeight = fmPaint.descent - fmPaint.ascent;
int drHeight = rect.bottom - rect.top;
int centerY = fmPaint.ascent + fontHeight / 2;
fontMetricsInt.ascent = centerY - drHeight / 2;
fontMetricsInt.top = fontMetricsInt.ascent;
fontMetricsInt.bottom = centerY + drHeight / 2;
fontMetricsInt.descent = fontMetricsInt.bottom;
}
return rect.right;
}
/**
* see detail message in android.text.TextLine
*
* @param canvas the canvas, can be null if not rendering
* @param text the text to be draw
* @param start the text start position
* @param end the text end position
* @param x the edge of the replacement closest to the leading margin
* @param top the top of the line
* @param y the baseline
* @param bottom the bottom of the line
* @param paint the work paint
*/
@Override
public void draw(Canvas canvas, CharSequence text, int start, int end,
float x, int top, int y, int bottom, Paint paint) {
Drawable drawable = getDrawable();
canvas.save();
Paint.FontMetricsInt fmPaint = paint.getFontMetricsInt();
int fontHeight = fmPaint.descent - fmPaint.ascent;
int centerY = y + fmPaint.descent - fontHeight / 2;
int transY = centerY - (drawable.getBounds().bottom - drawable.getBounds().top) / 2;
canvas.translate(x, transY);
drawable.draw(canvas);
canvas.restore();
}
}
Run Code Online (Sandbox Code Playgroud)
我通过创建一个继承自ImageSpan 的类得到了一个可行的解决方案。
然后修改 DynamicDrawableSpan 的绘制实现。至少当我的图像高度小于字体高度时,此实现有效。不知道这对于像你这样的更大的图像是如何工作的。
@Override
public void draw(Canvas canvas, CharSequence text,
int start, int end, float x,
int top, int y, int bottom, Paint paint) {
Drawable b = getCachedDrawable();
canvas.save();
int bCenter = b.getIntrinsicHeight() / 2;
int fontTop = paint.getFontMetricsInt().top;
int fontBottom = paint.getFontMetricsInt().bottom;
int transY = (bottom - b.getBounds().bottom) -
(((fontBottom - fontTop) / 2) - bCenter);
canvas.translate(x, transY);
b.draw(canvas);
canvas.restore();
}
Run Code Online (Sandbox Code Playgroud)
还必须重用 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<Drawable>(d);
}
return d;
}
private WeakReference<Drawable> mDrawableRef;
Run Code Online (Sandbox Code Playgroud)
这就是我如何使用它作为静态方法,在文本前面插入图像。
public static CharSequence formatTextWithIcon(Context context, String text,
int iconResourceId) {
SpannableStringBuilder sb = new SpannableStringBuilder("X");
try {
Drawable d = context.getResources().getDrawable(iconResourceId);
d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
CenteredImageSpan span = new CenteredImageSpan(d);
sb.setSpan(span, 0, sb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
sb.append(" " + text);
} catch (Exception e) {
e.printStackTrace();
sb.append(text);
}
return sb;
Run Code Online (Sandbox Code Playgroud)
考虑到本地化,也许这不是一个好的做法,但对我来说很有效。要将图像设置在文本中间,您自然需要将文本中的标记替换为跨度。
归档时间: |
|
查看次数: |
19999 次 |
最近记录: |