TextView实现图文混排

使用Html.fromHtml方法,解析html页面,并在Android TextView显示,实现图文混排

数据源,可以看到是html格式:

从API level 24开始,fromHtml(String)被废弃,使用fromHtml(String source, int flags) 代替

flags:
    FROM_HTML_MODE_COMPACT:html块元素之间使用一个换行符分隔
    FROM_HTML_MODE_LEGACY:html块元素之间使用两个换行符分隔

1
2
3
4
5
/* 
* source: html内容
* flags: 标记
*/
Html.fromHtml(String source, int flags);

    如果只使用以上两个参数,对应的方法只会实现html中的文字,图片会被绿色的小方块取代

所以我们要使用四个参数的Html.fromHtml()方法

1
2
3
4
5
6
7
/* 
* source: html内容
* flags: 标记
* imageGetter: 加载图片
* tagHandler: 识别其它很多标签
*/
Html.fromHtml(String source, int flags, ImageGetter imageGetter, TagHandler tagHandler)

页面布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:gravity="center"
android:orientation="vertical"
android:background="#ededed"
xmlns:android="http://schemas.android.com/apk/res/android">
<androidx.cardview.widget.CardView
android:layout_margin="10dp"
app:cardCornerRadius="5dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:background="@color/white"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:text="内容"
android:layout_margin="10dp"
android:id="@+id/textView"
android:textStyle="bold"
android:textColor="@color/black"
android:textSize="15sp"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>

重写ImageGetter类

创建MyImageGetter继承自Html.fromHtml()的第三个参数类,Html.ImageGetter,并重写了它的getDrawable方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LevelListDrawable;
import android.text.Html;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.CustomTarget;
import com.bumptech.glide.request.transition.Transition;

public class MyImageGetter implements Html.ImageGetter {
private Context context;
private TextView textView;

public MyImageGetter(Context context,TextView textView){
this.context = context;
this.textView = textView;
}

@Override
// source就是img中src的路径
public Drawable getDrawable(String source) {
// 实例化LevelListDrawable类,LevelListDrawable可以通过改变Level值来切换相应的图片
LevelListDrawable levelListDrawable = new LevelListDrawable();
// 使用Glide动态加载图片,通过asDrawable()指定返回类型为Drawable
Glide.with(context).asDrawable().load(source).into(new CustomTarget<Drawable>() {
@Override
// 图片加载回调
public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
// 把一个Drawable资源添加到LevelListDrawable
levelListDrawable.addLevel(1,1,resource);
levelListDrawable.setBounds(0,0,resource.getIntrinsicWidth(),resource.getMinimumHeight());//设置Drawable长宽
levelListDrawable.setLevel(1);//设置对象的级别值
textView.invalidate();//调用invalidate()重新绘制TextView界面
textView.setText(textView.getText());//设置重绘的TextView内容
}

@Override
public void onLoadCleared(@Nullable Drawable placeholder) {

}
});
return levelListDrawable;
}
}

getDrawable方法也可以这样写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    @Override
// source就是img中src的路径
public Drawable getDrawable(String source) {
// 实例化LevelListDrawable类,LevelListDrawable可以通过改变Level值来切换相应的图片
LevelListDrawable levelListDrawable = new LevelListDrawable();
// 使用Glide动态加载图片,通过asDrawable()指定返回类型为Drawable
Glide.with(context).asBitmap().load(source).into(new CustomTarget<Bitmap>() {
@Override
public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
if (resource != null){
BitmapDrawable bitmapDrawable = new BitmapDrawable(null,resource);
// 把一个Drawable资源添加到LevelListDrawable
levelListDrawable.addLevel(1,1,bitmapDrawable);
levelListDrawable.setBounds(0,0,resource.getWidth(),resource.getHeight());//设置Drawable长宽
levelListDrawable.setLevel(1);//设置对象的级别值
textView.invalidate();//调用invalidate()重新绘制TextView界面
textView.setText(textView.getText());//设置重绘的TextView内容
}
}
@Override
public void onLoadCleared(@Nullable Drawable placeholder) {

}
});
return levelListDrawable;
}

设置TextView

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package com.xin.SmartCity;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Build;
import android.os.Bundle;
import android.text.Html;
import android.widget.TextView;

import com.xin.SmartCity.home.MyImageGetter;

public class TestActivity extends AppCompatActivity {
private TextView textView;
private String content;
private MyImageGetter myImageGetter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
init();
setContent();
}

private void setContent() {
// 从api 24开始,原Html.fromHtml被废弃
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
// 传入对应参数,因为没有其他标签设置,对后一个参数直接填null
textView.setText(Html.fromHtml(content,Html.FROM_HTML_MODE_COMPACT,myImageGetter,null));
}
}

private void init() {
textView = findViewById(R.id.textView);
myImageGetter = new MyImageGetter(this,textView);//实例化重写的ImageGetter类
// 内容
content = "<p>测试文本1</p>\n" +
"<p>测试文本2</p>\n" +
"<img src=\"https://www.baidu.com/img/flexible/logo/pc/result.png\" />\n" +
"<p>测试文本1</p>\n" +
"<p>测试文本2</p>\n" +
"<img src=\"https://www.baidu.com/img/flexible/logo/pc/result.png\" />\n" +
"<p>测试文本1</p>\n" +
"<p>测试文本2</p>\n" +
"<img src=\"https://www.baidu.com/img/flexible/logo/pc/result.png\" />\n" +
"<p>测试文本1</p>\n" +
"<p>测试文本2</p>\n" +
"<img src=\"https://www.baidu.com/img/flexible/logo/pc/result.png\" />";
}
}

效果展示