#Android筆記# 超級足球app 開發總結(二)—— SpannableString根據標記插入文字實現圖文混排

最近利用業餘時間,開發了一款基於懂球帝接口數據的足球資訊app,整體的UI也是仿照懂球帝設計的。這是一個比較綜合的項目,用到了不少以前沒用過的組件和api,而且產生了很多新的開發思路,有些實現方式也是自己琢磨的,所以值得做一些記錄,可能還存在瑕疵和可以優化的地方,也希望大家給我多指正。

先來看看實現前後的對比圖:

再來看一看接口返回的數據(數據結構比較長,這裏只截取了部分用到的數據):

可以看到,懂球帝這裏是通過file_name去跟文本中對應的標記匹配來實現圖文混排的,而不是通過html格式去做的,因此我這裏想到的是通過在spannableString中插入圖片的方式去實現混排。

思路整理

1、通過glide將圖片下載下來;

Glide.with(context).load(a.getUrl()).into(new SimpleTarget<Drawable>() {
    @Override
    public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
     
    }
});

2、利用String的indexOf函數,通過匹配file_name,找到圖片在文本中的位置;

int startIndex = circle.getContent().indexOf(a.getFile_name());
int endIndex = startIndex+a.getFile_name().length();

3、利用spannableString的setSpan函數,將圖片插入到對應位置;

spannableString.setSpan(imageSpan, startIndex,endIndex, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);

遇到的問題

1、下載圖片是需要通過異步方式去實現的,那麼我就沒法控制 當所有圖片都下載完成後再通知TextView更新文本了。

解決辦法:後來發現spannableString的setSpan()並不會覆蓋上一次的樣式,而是類似於addSpan的效果,因此我的解決方法就是每加載完一張圖片,就setSpan()一次,更新一次樣式;

spannableString.setSpan(imageSpan, startIndex,endIndex, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
handler.sendEmptyMessage(i);
Handler handler = new Handler(){
    @Override
    public void handleMessage(Message msg) {
        tvContent.setText(spannableString);
    }
};

2、setSpan之後,文本的{{p1}}、{{p2}}等處確實不顯示了,但圖片未加載到對應位置。

解決辦法:出現這種問題的原因是沒有對圖片的寬高進行設置,需要調用drawable的setBounds()設置圖片的大小。

//設置圖片顯示的寬高
resource.setBounds(0,0,(int)picWidth,(int)picHeight);

3、圖片與文字之間的行高與文件間的行高不一致;

解決辦法:首先去除文本中多餘的空行

public static String deleteCRLF(String input) {
    return input.replaceAll("((\r\n)|\n)[\\s\t ]*(\\1)+", "$1").replaceAll("^((\r\n)|\n)", "");
}

然後對ImageSpan做一些處理(這個是我直接上網百度的,原理有待研究)

public class MyImageSpan extends ImageSpan {

    public MyImageSpan( Drawable b) {
        super(b);
    }

    @Override
    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;
        //要顯示的文本高度-圖片高度除2等居中位置+top(換行情況)
        transY = ((bottom - top) - b.getBounds().bottom) / 2 + top;
        //偏移畫布後開始繪製
        canvas.translate(x, transY);
        b.draw(canvas);
        canvas.restore();
    }

}

最終實現

     Handler handler = new Handler(){
                        @Override
                        public void handleMessage(Message msg) {
                            tvContent.setText(spannableString);
                        }
                    };
                    for(CircleNews.Attachment a: circle.getAttachments()){
                        Glide.with(context).load(a.getUrl()).into(new SimpleTarget<Drawable>() {
                            @Override
                            public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
                                MyImageSpan imageSpan = new MyImageSpan(resource);
                                //ImageSpan imageSpan = new ImageSpan(resource);
                                double picWidth = UIUtils.getScreenWidth(context);
                                double ratio = picWidth/(double)resource.getIntrinsicWidth();
                                double picHeight = ratio*resource.getIntrinsicHeight();
                                //設置圖片顯示的寬高
                                resource.setBounds(0,0,(int)picWidth,(int)picHeight);
                                int i = circle.getAttachments().indexOf(a);
                                int startIndex = circle.getContent().indexOf(a.getFile_name());
                                int endIndex = startIndex+a.getFile_name().length();
                                spannableString.setSpan(imageSpan, startIndex,
                                        endIndex, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
                                handler.sendEmptyMessage(i);
                            }
                        });

                    }

總結

之前處理富文本通常是通過html樣式的去實現的;通過研究懂球帝的這個api接口,又獲得了一種新的思路:可以通過SpannableString+文本標記的方式去實現富文本,使用SpannableString的好處是可以實現高度的自定義,比如說插入一個自定義表情,使用SpannableString只需在文本中增加一個標記識別即可,而使用html樣式的話,就相對複雜了。實現這種圖文混排的方式應該還有很多,如果你耐心看到這裏,不妨留下你的一些想法吧,我們可以一起交流,共同進步!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章