Align text around ImageSpan center vertical

前端 未结 9 1872
抹茶落季
抹茶落季 2020-11-28 23:59

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

9条回答
  •  孤街浪徒
    2020-11-29 00:15

    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.

    Here's my class example:

    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 wr = mDrawableRef;
            Drawable d = null;
    
            if (wr != null)
                d = wr.get();
    
            if (d == null) {
                d = getDrawable();
                mDrawableRef = new WeakReference<>(d);
            }
    
            return d;
        }
    
        private WeakReference mDrawableRef;
    }
    

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

提交回复
热议问题