最近要展示html在textView上,实现图文混排,并且图片可以点击放大,所以去研究了一下,效果图如下:
我们知道textView的setText(Html.fromHtml(html))可以直接展示html的内容,但是如果html的标签包含imgd的话,直接用这个方法图片会展示不出来,然后我们看fromHtml的另一个构造方法的源码:
public static Spanned fromHtml(String source, ImageGetter imageGetter,
TagHandler tagHandler) {
Parser parser = new Parser();
try {
parser.setProperty(Parser.schemaProperty, HtmlParser.schema);
} catch (org.xml.sax.SAXNotRecognizedException e) {
// Should not happen.
throw new RuntimeException(e);
} catch (org.xml.sax.SAXNotSupportedException e) {
// Should not happen.
throw new RuntimeException(e);
}
HtmlToSpannedConverter converter =
new HtmlToSpannedConverter(source, imageGetter, tagHandler,
parser);
return converter.convert();
}
通过上面的代码我们知道要想展示图片,我们可以重写imageGetter,下面是我重写imageGetter:
public class MImageGetter implements ImageGetter{
Context c;
TextView container;
public MImageGetter(TextView text,Context c) {
this.c = c;
this.container = text;
}
public Drawable getDrawable(String source) {
final LevelListDrawable drawable = new LevelListDrawable();
Glide.with(c).load(source).asBitmap().into(new SimpleTarget() {
@Override
public void onResourceReady(Bitmap resource, GlideAnimation super Bitmap> glideAnimation) {
if(resource != null) {
BitmapDrawable bitmapDrawable = new BitmapDrawable(resource);
drawable.addLevel(1, 1, bitmapDrawable);
drawable.setBounds(0, 0, resource.getWidth(),resource.getHeight());
drawable.setLevel(1);
container.invalidate();
container.setText(container.getText());
}
}
});
return drawable;
}
}
加载图片的时候我用的是glide异步加载,其他原理一样。现在图片已经可以正常展示出来了,接下来要获取它的点击事件,这就首先需要设置textView的setMovementMethod方法,然后重写LinkMovementMethod获取到点击事件:
/**
* 重写LinkMovementMethod类,获取图片的点击事件
*/
public class LinkMovementMethodExt extends LinkMovementMethod {
private static LinkMovementMethod sInstance;
private Handler handler = null;
private Class spanClass = null;
public static MovementMethod getInstance(Handler _handler,Class _spanClass) {
if (sInstance == null) {
sInstance = new LinkMovementMethodExt();
((LinkMovementMethodExt)sInstance).handler = _handler;
((LinkMovementMethodExt)sInstance).spanClass = _spanClass;
}
return sInstance;
}
int x1;
int x2;
int y1;
int y2;
@Override
public boolean onTouchEvent(TextView widget, Spannable buffer,
MotionEvent event) {
int action = event.getAction();
if (event.getAction() == MotionEvent.ACTION_DOWN){
x1 = (int) event.getX();
y1 = (int) event.getY();
}
if (event.getAction() == MotionEvent.ACTION_UP) {
x2 = (int) event.getX();
y2 = (int) event.getY();
if (Math.abs(x1 - x2) < 10 && Math.abs(y1 - y2) < 10) {
x2 -= widget.getTotalPaddingLeft();
y2 -= widget.getTotalPaddingTop();
x2 += widget.getScrollX();
y2 += widget.getScrollY();
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y2);
int off = layout.getOffsetForHorizontal(line, x2);
/**
* get you interest span
*/
Object[] spans = buffer.getSpans(off, off, spanClass);
if (spans.length != 0) {
Selection.setSelection(buffer,
buffer.getSpanStart(spans[0]),
buffer.getSpanEnd(spans[0]));
MessageSpan obj = new MessageSpan();
obj.setObj(spans);
obj.setView(widget);
Message message = handler.obtainMessage();
message.obj = obj;
message.what = 200;
message.sendToTarget();
return true;
}
}
}
return super.onTouchEvent(widget, buffer, event);
}
public boolean canSelectArbitrarily() {
return true;
}
public boolean onKeyUp(TextView widget, Spannable buffer, int keyCode,
KeyEvent event) {
return false;
}
}
这样,我们就可以在mainactivity里面根据需要处理了:
public class MainActivity extends AppCompatActivity {
private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.tv);
ScrollView sv = (ScrollView) findViewById(R.id.sv);
final String html = "下面是第一张图片了 " + "" +
"这也是第二张图片" + "" +
"最后一张" + "";
tv.setText(Html.fromHtml(html, new MImageGetter(tv, getApplicationContext()), null));
final Handler handler = new Handler() {
public void handleMessage(Message msg) {
int what = msg.what;
if (what == 200) {
MessageSpan ms = (MessageSpan) msg.obj;
Object[] spans = (Object[]) ms.getObj();
final ArrayList list = new ArrayList<>();
for (Object span : spans) {
if (span instanceof ImageSpan) {
Log.i("picUrl==", ((ImageSpan) span).getSource());
list.add(((ImageSpan) span).getSource());
Intent intent = new Intent(getApplicationContext(), ImageGalleryActivity.class);
intent.putStringArrayListExtra("images", list);
startActivity(intent);
}
}
}
}
};
tv.setMovementMethod(LinkMovementMethodExt.getInstance(handler, ImageSpan.class));
}
}
上面的代码判断span是否是imagespan,如果是的话,我们就获取到它的地址,然后进行相应的操作。
到了这里,利用textView展示html,进行图文混排就完成了。