Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Align text around ImageSpan center vertical

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.

Here is a sample, the outline shows bounds of the TextView: enter image description here

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:

enter image description here

Here are the constraints that I'm bound by:

  • I cannot use compound drawables. The images must be able to be shown between words.
  • The text may be multiline depending on the content. I have no control over this.
  • My images are larger than the surrounding text and I cannot reduce their size. While the sample image above is larger than the actual images (to demonstrate the current behavior), the actual images are still large enough that this problem is noticeable.

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.

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.

Any and all help is appreciated!

like image 506
Karakuri Avatar asked Sep 02 '14 16:09

Karakuri


People also ask

How do I align text next to an image vertically?

Use the align-items property with the "center" value to place the items at the center of the container. Set the justify-content property to "center". Put the image's maximum width to 100% with the max-width property. Set the flex-basis property of the "image" class to specify the initial main size of your image.

How do I align text to the center of an image in HTML?

An <img> element is an inline element (display value of inline-block ). It can be easily centered by adding the text-align: center; CSS property to the parent element that contains it. To center an image using text-align: center; you must place the <img> inside of a block-level element such as a div .


1 Answers

My answer tweaks the first answer. Actually I have tried both two methods above, and I don't think they are really center vertical. It would make the drawable more center if it's placed in between ascent and descent, rather than top and bottom. So as to the second answer, it aligns the center of the drawable to the baseline of the text, rather than the center of that text. Here's my solution:

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;   } } 

I also rewrite getSize to keep the FontMetrics of drawable the same as other text, otherwise the parent view won't wrap the content correctly.

like image 110
misaka-10032 Avatar answered Oct 16 '22 14:10

misaka-10032