工作太忙,不做过多的解释了,核心是用到了 SpannableStringBuilder  Glide  和 Rxjava

直接上代码了,就两个类。

public class ImageSpanAsyncLoad {

    public ImageSpanAsyncLoad() {

    }

    @SuppressLint("StaticFieldLeak")
public void displayTextAndImage(List<SkuDeliveryBean> skuDelivery, final String title, final TextView textView) { if (TextUtils.isEmpty(title)) {
return;
} final StringBuilder stringBuilder;
if (skuDelivery != null && skuDelivery.size() > 0) {
stringBuilder = new StringBuilder(" " + title);
} else {
stringBuilder = new StringBuilder(title);
}
textView.setText(stringBuilder); // List<String> tagPathList = getProductDelivery(skuDelivery);
if (skuDelivery == null || skuDelivery.size() <= 0) {
return;
} // 创建下载任务
List<Observable<ResultTask>> tempTaskList = new ArrayList<>();
for (int i = 0; i < skuDelivery.size(); i++) {
DownloadTask task = new DownloadTask(i, skuDelivery.get(i).getSkuDeliveryUrl());
task.width = skuDelivery.get(i).getWidth();
task.height = skuDelivery.get(i).getHeight();
tempTaskList.add(createDownaloadTask(task));
stringBuilder.insert(0, " ");
} // 合并任务
Observable.mergeDelayError(tempTaskList)
.subscribeOn(Schedulers.newThread())
.unsubscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<ResultTask>() { Disposable mD;
List<ResultTask> temp = new ArrayList<>(); @Override
public void onSubscribe(Disposable d) {
mD = d;
} @Override
public void onNext(ResultTask resultTask) {
temp.add(resultTask);
} @Override
public void onError(Throwable e) { } @Override
public void onComplete() {
if (mD != null) {
mD.dispose();
} // 排序
Collections.sort(temp, new Comparator<ResultTask>() {
@Override
public int compare(ResultTask o1, ResultTask o2) {
return o1.position - o2.position;
}
}); // 开始绘制
SpannableStringBuilder sb = new SpannableStringBuilder();
sb.append(stringBuilder.toString());
for (int i = 0; i < temp.size(); i++) {
ResultTask task = temp.get(i);
float radio = (float) SizeUtils.dp2px(task.height) / task.drawable.getIntrinsicHeight();
task.drawable.setBounds(0, 0, (int) (task.drawable.getIntrinsicWidth() * radio), SizeUtils.dp2px(task.height));
CenterAlignImageSpan imageSpan = new CenterAlignImageSpan(task.drawable);
sb.setSpan(imageSpan, i, i + 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
textView.setText(sb);
}
}); } // 创建下载任务
private Observable<ResultTask> createDownaloadTask(DownloadTask downloadTask) { Observable<ResultTask> temp; temp = Observable.just(downloadTask)
.observeOn(Schedulers.newThread())
.flatMap(new Function<DownloadTask, ObservableSource<ResultTask>>() {
@Override
public ObservableSource<ResultTask> apply(DownloadTask downloadTask) throws Exception { ResultTask resultTask = new ResultTask();
resultTask.position = downloadTask.position;
resultTask.width = downloadTask.width;
resultTask.height = downloadTask.height; // 下图片
if (downloadTask.drawable != null) {
resultTask.drawable = downloadTask.drawable;
} else {
resultTask.drawable = GlideApp.with(BaseApplication.getInstance())
.asDrawable()
.load(downloadTask.imgUrl)
.submit()
.get();
} return Observable.just(resultTask);
}
}); return temp; } /**
* 设置标签
*
* @param skuDelivery 全球购 次日达 等网络图片
* @param title 标题
* @param textView view
* @param tag 自营非自营等
*/
@SuppressLint("StaticFieldLeak")
public void displayTextAndImage(List<SkuDeliveryBean> skuDelivery, final String title, final TextView textView, final String tag) { if (TextUtils.isEmpty(title)) {
return;
} final StringBuilder stringBuilder;
if (skuDelivery != null && skuDelivery.size() > 0) {
stringBuilder = new StringBuilder(" " + title);
} else {
stringBuilder = new StringBuilder(title);
}
textView.setText(stringBuilder);
// 创建下载任务
List<Observable<ResultTask>> tempTaskList = new ArrayList<>();
int j = 0;
//有标签手动设置drawable
if (!TextUtils.isEmpty(tag)) {
//R.layout.tag是每个标签的布局
View view = LayoutInflater.from(textView.getContext()).inflate(R.layout.tag, null);
TextView tv_tag = view.findViewById(R.id.tv_tag);
tv_tag.setText(tag);
view.setDrawingCacheEnabled(true);
view.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
Bitmap bitmap = ConvertUtils.view2Bitmap(view);
Drawable drawable = ConvertUtils.bitmap2Drawable(bitmap);
tempTaskList.add(createDownaloadTask(new DownloadTask(0, drawable)));
stringBuilder.insert(j, " ");
j = j + 1;
view.destroyDrawingCache();
} List<String> tagPathList = getProductDelivery(skuDelivery);
if (tagPathList != null && tagPathList.size() > 0) {
for (int i = 0; i < tagPathList.size(); i++) {
if (TextUtils.isEmpty(tagPathList.get(i))) {
continue;
}
tempTaskList.add(createDownaloadTask(new DownloadTask(i + 1, tagPathList.get(i))));
stringBuilder.insert(j, " ");
}
} if (tempTaskList.size() <= 0) {
return;
}
// 合并任务
Observable.mergeDelayError(tempTaskList)
.subscribeOn(Schedulers.newThread())
.unsubscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<ResultTask>() { Disposable mD;
List<ResultTask> temp = new ArrayList<>(); @Override
public void onSubscribe(Disposable d) {
mD = d;
} @Override
public void onNext(ResultTask resultTask) {
temp.add(resultTask);
} @Override
public void onError(Throwable e) { } @Override
public void onComplete() {
if (mD != null) {
mD.dispose();
} // 排序
Collections.sort(temp, new Comparator<ResultTask>() {
@Override
public int compare(ResultTask o1, ResultTask o2) {
return o1.position - o2.position;
}
}); // 开始绘制
SpannableStringBuilder sb = new SpannableStringBuilder();
sb.append(stringBuilder.toString());
for (int i = 0; i < temp.size(); i++) {
ResultTask task = temp.get(i);
float dpValue = 24;
if (!TextUtils.isEmpty(tag) && i == 0) {
dpValue = 16;
}
float radio = (float) SizeUtils.dp2px(dpValue) / task.drawable.getIntrinsicHeight();
task.drawable.setBounds(0, 0, (int) (task.drawable.getIntrinsicWidth() * radio), SizeUtils.dp2px(dpValue));
CenterAlignImageSpan imageSpan = new CenterAlignImageSpan(task.drawable);
sb.setSpan(imageSpan, i, i + 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
textView.setText(sb);
}
}); } // 下载任务类
private static class DownloadTask {
private int position;
private String imgUrl;
private int width;
private int height;
private Drawable drawable; public DownloadTask(int position, String imgUrl) {
this.position = position;
this.imgUrl = imgUrl;
} public DownloadTask(int position, Drawable drawable) {
this.position = position;
this.drawable = drawable;
}
} // 承载任务的类
private static class ResultTask {
private int position;
private Drawable drawable;
private int width;
private int height;
} /**
* 转化标签
*/
private List<String> getProductDelivery(List<SkuDeliveryBean> skuDelivery) {
List<String> temp = new ArrayList<>();
if (skuDelivery != null) {
for (SkuDeliveryBean bean : skuDelivery) {
if (bean == null) {
continue;
}
temp.add(bean.getSkuDeliveryUrl());
}
}
return temp;
}
}

ImageSpan

public class CenterAlignImageSpan extends ImageSpan {

    public CenterAlignImageSpan(Drawable drawable) {
super(drawable);
} @Override
public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
Drawable d = getDrawable();
Rect rect = d.getBounds();
if (fm != null) {
Paint.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;
} @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 = 0;
transY = ((bottom - top) - b.getBounds().bottom) / 2 + top;
canvas.translate(x, transY);
b.draw(canvas);
canvas.restore();
} }

Android-textview图文混排(网络图片)的更多相关文章

  1. TextView图文混排

    大家都知道,textView有一个setCompoundDrawables的方法来设置上下左右位置的图标,当然,也可以在xml布局文件中设置,然而问题来了,假如我们把图标放在左边,当我们让TextVi ...

  2. TextView + Spanned实现图文混排以及图片点击交互

    最近要实现图文混排的需求,webview过大,所以想到了用SpannableStringBuilder来实现. 不过参考了大量国内文章,大多数是教你如何实现图文混排,并没有提及图片点击交互的.有翻阅了 ...

  3. Android TextView图文混合编排

    Android TextView图文混合编排 实现技术细节不难,两个要点:1.html代码的混合编写.2,重写ImageGetter.例如:布局: <?xml version="1.0 ...

  4. Android 自绘TextView解决提前换行问题,支持图文混排

    先看下效果图: 上面是MTextView,下面是默认的TextView. 一.原因 用最简单的全英文句子为例,如果有一个很长的单词,这一行剩余的空间显示不下了,那么规则就是不打断单词,而是把整个单词丢 ...

  5. Android TextView中图文混排设置行间距导致高度不一致问题解决

    最近项目中需要实现一个评论带表情的功能,刚开始一切顺利,非常easy,突然有一天发现文字跟表情混排的时候,TextView中图文高度不一致,excuse...什么鬼,之前明明测试过图文混排,不存在这个 ...

  6. Android中Textview显示Html,图文混排,支持图片点击放大

    本文首发于网易云社区 对于呈现Html文本来说,Android提供的Webview控件可以得到很好的效果,但使用Webview控件的弊端是效率相对比较低,对于呈现简单的html文本的话,杀鸡不必使用牛 ...

  7. android:怎样在TextView实现图文混排

    我们通常在TextView文本中设置文字.但是怎样设置图文混排呢? 我就在这里写一个样例 .我们须要用到一点简单的HTML知识 在TextView中预订了一些类似HTML的标签,通过标签能够使Text ...

  8. 使用android SpannableStringBuilder实现图文混排

    项目开发中需要实现这种效果 多余两行,两行最后是省略号,省略号后面是下拉更多 之前用过的是Html.fromHtml去处理图文混排的,仅仅是文字后图片或者文字颜色字体什么的, 但是这里需要在最后文字的 ...

  9. 使用android SpannableStringBuilder实现图文混排,看到许多其他

    项目开发需要达到这种效果 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZmFuY3lsb3ZlamF2YQ==/font/5a6L5L2T/fontsiz ...

  10. Android自动解析html带图片,实现图文混排

    在android中,如何将html代码转换为text,然后显示在textview中呢,有一个简单直接的方法: textView.setText(Html.fromHtml(content)); 然而用 ...

随机推荐

  1. 深入理解OkHttp源码(二)——获取响应

    首先先看一张流程图,该图是从拆轮子系列:拆 OkHttp 中盗来的,如下: 在上一篇博客深入理解OkHttp源码(一)——提交请求中介绍到了getResponseWithInterceptorChai ...

  2. Android--使用剪切板在Activity中传值

    在Activity之间传递数据还可以利用一些技巧,不管windows还是Linux操作系统,都会支持一种叫剪切板的技术,也就是某一个程序将一些数据复制到剪切板上,然后其他的任何程序都可以从剪切板中获取 ...

  3. solr调用lucene底层实现倒排索引源码解析

    1.什么是Lucene? 作为一个开放源代码项目,Lucene从问世之后,引发了开放源代码社群的巨大反响,程序员们不仅使用它构建具体的全文检索应用,而且将之集成到各种系统软件中去,以及构建Web应用, ...

  4. 你可能没听过的11个Python库

    目前,网上已有成千上万个Python包,但几乎没有人能够全部知道它们.单单 PyPi上就有超过47000个包列表. 现在,越来越多的数据科学家开始使用Python,虽然他们从 pandas, scik ...

  5. 浅谈SpringAOP

    0. 写在最前面 之前实习天天在写业务,其中有一个业务是非常的复杂,涉及到了特别多的表.最后测下来,一个接口的时间,竟然要5s多. 当时想写一个AOP,来计算处理接口花费多长时间,也就是在业务逻辑的前 ...

  6. python bytes和bytearray、编码和解码

    str.bytes和bytearray简介 str是字符数据,bytes和bytearray是字节数据.它们都是序列,可以进行迭代遍历.str和bytes是不可变序列,bytearray是可变序列,可 ...

  7. go基础系列:简介

    1.Go简介 Go语言是编译型.静态类型的类C的语言,并带有GC(垃圾收集器,garbage collection).这意味着什么? 另外,Go是一种非常严格的语言,它几乎总是要求我们"以标 ...

  8. 第一册:lesson seventy seven。

    原文:terrible toothache. Good morning Mr.Croft. Good morning nurse. I want to see the dentist,please. ...

  9. ASP.NET WEB API简介

      ASP.NET WEB API是基于.NET Framework用来构建Restful软件架构的框架,它是基于HTTP协议.Http不只是能够生成我们常见的web页面,它更是能够建立服务和面向资源 ...

  10. ORA-00959: tablespace 'PSAPTEMP' does not exist

    错误 : ORA-00959: tablespace 'PSAPTEMP' does not exist 解决办法: CREATE TEMPORARY TABLESPACE PSAPTEMP  TEM ...