TextView的图文混排

五种方法:

  1. drawableLeft、drawableTop。。(TextView中xml自带,通过drawPadding控制间距)
  2. 自定义TextView,重写TextView的Ondraw方法

BitmapFactory获取bitmap对象

    @Override
    protected void onDraw(Canvas canvas) {
    canvas.drawBitmap(mBitmap, 0, 0, getPaint());
      super.onDraw(canvas);
 }

缺点:不能灵活控制图片位置

  1. 使用html,安卓api支持
    textView = (TextView) findViewById(R.id.tv);
        String html = "<img src='" + R.drawable.ding + "'/>";
        html += " <img  src='" + R.drawable.jing + "' />";
        ImageGetter imgGetter = new ImageGetter() {
            @Override
            public Drawable getDrawable(String source) {
                // TODO Auto-generated method stub
                int id = Integer.parseInt(source);
                Drawable d = getResources().getDrawable(id);
                d.setBounds(0, 0, d.getIntrinsicWidth() + 10, d.getIntrinsicHeight() + 10);
                return d;
            }
        };
        CharSequence charSequence = Html.fromHtml(html, imgGetter, null);
        textView.setText(charSequence);
        textView.append("  Html实现图文混排");
  1. imageSpan
textViewImageSpan= (TextView) findViewById(R.id.textViewImageSpan);
Bitmap bitmap= BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher);
//根据Bitmap对象创建ImageSpan对象
ImageSpan imageSpan=new ImageSpan(this,bitmap);
//创建一个SpinnableString对象,以便插入ImageSpan对象封装的图像
SpannableString spannableString=new SpannableString("replace");
//用ImageSpan对象替换replace字符串
spannableString.setSpan(imageSpan,0,7, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
//将图像显示在TextView上
textViewImageSpan.setText(spannableString);
  1. 扩展图片文字单行之间居中(间距字体大小都不影响)
private TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = (TextView) findViewById(R.id.tv);
        SpannableString showString = new SpannableString(
                "我    钟山风雨起苍黄百万雄师过大江虎踞龙盘今胜昔天翻地覆慨而慷宜将剩勇追穷寇不可沽名学霸王天若有情天亦老人间正道是沧桑。钟山风雨起苍黄百万雄师过大江虎踞龙盘今胜昔天翻地覆慨而慷宜将剩勇追穷寇不可沽名学霸王天若有情天亦老人间正道是沧桑。");
        MyIm imageSpan = new MyIm(this, R.drawable.ding);
        MyIm imageSpan2 = new MyIm(this, R.drawable.jing);
        showString.setSpan(imageSpan, 2, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        showString.setSpan(imageSpan2, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        textView.setText(showString);
    }
    public class MyIm extends ImageSpan {
        public MyIm(Context arg0, int arg1) {
            super(arg0, arg1);
        }
        public int getSize(Paint paint, CharSequence text, int start, int end, FontMetricsInt fm) {
            Drawable d = getDrawable();
            Rect rect = d.getBounds();
            if (fm != null) {
                FontMetricsInt fmPaint = paint.getFontMetricsInt();
                // 获得文字、图片高度
                int fontHeight = fmPaint.bottom - fmPaint.top;
                int drHeight = rect.bottom - rect.top;
                int top = drHeight / 2 - fontHeight / 4;
                int bottom = drHeight / 2 + fontHeight / 4;
                fm.ascent = -bottom;
                fm.top = -bottom;
                fm.bottom = top;
                fm.descent = top;
            }
            return rect.right;
        }
//getSize方法,返回一个Int含义为图片的宽度还设置了文字的ascent、descent的位置

        @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;
            canvas.save();
            canvas.translate(x, transY);
            b.draw(canvas);
            canvas.restore();
        }
    }

先解释一个类:Paint.FontMetrics,它表示绘制字体时的度量标准。google的官方api文档对它的字段说明如下:
ascent: 字体最上端到基线的距离
descent:字体最下端到基线的距离

Paste_Image.png

回到主题,我们要让imagespan与text对齐,只需把imagespan放到descent线和ascent线之间的中间位置就可以了。

解释下形参:
x,要绘制的image的左边框到textview左边框的距离。
y,要替换的文字的基线坐标,即基线到textview上边框的距离。
top,替换行的最顶部位置。
bottom,替换行的最底部位置。注意,textview中两行之间的行间距是属于上一行的,所以这里bottom是指行间隔的底部位置。
paint,画笔,包含了要绘制字体的度量信息。
这几个参数含义在代码中找不到说明,写了个demo测出来的。top和bottom参数只是解释下,函数里面用不上。
然后解释下代码逻辑:
getDrawable获取要绘制的image,getBounds是获取包裹image的矩形框尺寸;
y + fm.descent得到字体的descent线坐标;
y + fm.ascent得到字体的ascent线坐标;
两者相加除以2就是两条线中线的坐标;
b.getBounds().bottom是image的高度(试想把image放到原点),除以2即高度一半;
前面得到的中线坐标减image高度的一半就是image顶部要绘制的目标位置;
最后把目标坐标传递给canvas.translate函数就可以了
显示效果:

Paste_Image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容