1. 程式人生 > >Android 解決圖文混排,圖片和文字居中對齊問題(ImageSpan)

Android 解決圖文混排,圖片和文字居中對齊問題(ImageSpan)

一. 概述

眾所周知,Android圖文混排可以通過SpannableString來實現,通過在相應位置使用ImageSpan替換即可,但是使用過的人會發現,imageSpan只提供了兩種對齊方式,如下所示:

    /**
     底部對齊
     */
    public static final int ALIGN_BOTTOM = 0;

    /**
     基線對齊
     */
    public static final int ALIGN_BASELINE = 1;

但是在大多數時候,我們希望實現圖片的中點和文字的中點對齊(視覺設計師肯定會給到這樣的要求),那麼該怎麼辦呢?

二. 圖文混排,圖片居中對齊方案

方案1:

一個比較簡單解決方案就是讓圖片和文字的高度保持一致,這樣就變相居中對齊了,那麼有一些朋友為難了,視覺給的圖片的高度比字型的高度小,這腫麼辦? 這個問題很好解決,讓視覺給你切大一點的圖片,即在原來的圖片上多切一些透明的白邊。(是不是恍然大悟?哈哈)

plus:圖片比文字高的情況根本不需要居中對齊。

方案2:

程式設計師肯定有程式設計師的方案,那就是擴充套件繼承ImageSpan,重寫它的onDraw()方法。這個方案本人蔘考了網上的一些解決方案,但是都有侷限性,有些方案只要設定的TextView行間距或者padding就不能正常工作了。

這篇部落格的方案,在設定了行間距的時候,就出現問題了。但是這篇部落格把字型繪製的原理說的很清楚了,建議大家先讀這篇部落格,再來理解本人的做法。

程式碼展示

好了,直接上程式碼,這是自定義ImageSpan的程式碼,非常少。主要的原理是把圖片繪製在字型的descent線和ascent的中點位置。還是那句話,先看上面那篇部落格。

public class CenterAlignImageSpan extends ImageSpan {

    public CenterAlignImageSpan(Drawable drawable) {
        super(drawable);

    }

    public
CenterAlignImageSpan(Bitmap b) { super(b); } @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 = getDrawable(); Paint.FontMetricsInt fm = paint.getFontMetricsInt(); int transY = (y + fm.descent + y + fm.ascent) / 2 - b.getBounds().bottom / 2;//計算y方向的位移 canvas.save(); canvas.translate(x, transY);//繪製圖片位移一段距離 b.draw(canvas); canvas.restore(); } }

使用和執行效果

在佈局檔案裡放置一個TextView,設定其行間距。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    tools:context="com.example.hzwangqinwei.test.MainActivity"
    >

    <TextView
        android:id="@+id/test"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#aeae34"
        android:gravity="center"
        android:lineSpacingExtra="40dp"
        android:textSize="70dp"
        />

</LinearLayout>

activity裡的程式碼如下展示:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView tv = (TextView) findViewById(R.id.test);

        SpannableString sp = new SpannableString("圖文混排測排測試圖文混排測試圖文混排測試圖文混排測試圖");

        //獲取一張圖片
        Drawable drawable = getDrawable(R.drawable.star);
        drawable.setBounds(0, 0, drawable.getMinimumWidth(), drawable.getMinimumHeight());

        //居中對齊imageSpan
        CenterAlignImageSpan imageSpan = new CenterAlignImageSpan(drawable);
        sp.setSpan(imageSpan, 0, 1, ImageSpan.ALIGN_BASELINE);

        //普通imageSpan 做對比
        ImageSpan imageSpan2 = new ImageSpan(drawable);
        sp.setSpan(imageSpan2, 3, 4, ImageSpan.ALIGN_BASELINE);

        tv.setText(sp);
    }
}

執行效果,第二張圖片是普通的ImageSpan的效果,這裡加入進來是做一個對比。
image